Podziękowania Projekt tej książki powstał w trakcie rozmów z Debrą Williams Cauley, która jest re- daktorem w wydawnictwie IDG Books. Prowadziła cały ...
Podziękowania Projekt tej książki powstał w trakcie rozmów z Debrą Williams Cauley, która jest redaktorem w wydawnictwie IDG Books. Prowadziła cały projekt, znajdowała dodatkowych współpracowników oraz izolowała naiwnych początkujących autorów od twardej rzeczywistości przemysłu wydawniczego. Susan Christopherson pracowała jako redaktor projektu, zanim przekazała pałeczkę Barb Guerra, która z kolei przekształciła nasze chaotyczne notatki w rękopis. Bob Campbell przepisał go z niesłychaną szybkością. Richard Lynch był naszym recenzentem technicznym. Powstrzymał nas od napisania wielu rzeczy, które nie są prawdziwe, dał nam wiele dobrych rad, w jaki sposób ulepszyć wskazówki i przykłady. Pomógł nam napisać dużo lepszą książkę. Jednak nie jego należy winić za błędy i braki, które jeszcze pozostały.
Nie stworzyliśmy tej książki sami. Dustin Mitchell napisał rozdział o bezpieczeństwie i szyfrowaniu, Patrick McCuller jest autorem pierwszego szkicu rozdziałów o XML i OOP. Ariel Garcia współpracowała w trakcie powstawania pierwszych projektów rozdziałów na temat PHP i JavaScript. Współpracownicy Joyce w firmie Epinions (szczególnie Lou Montuli i Jay Ashton) również zasługują na wdzięczność za współpracę przy tworzeniu przykładów kodu oraz za wskazówki, jak używać PHP w silnie obciążonym środowisku. Szczególne podziękowania należą się twórcom PHP (a to: Rasmus Lerdorf, Zeev Sura-
oraz wielu ich współpracowników) ludziom, którzy tworzyli dokumentację do PHP (m.in. Stig Bakken, Alexander Aulbach, Egon Schmid, Lars Torben Wilson, Jim Winstead) oraz wszystkim z listy dyskusyjnej o PHP. Szczególnie dziękujemy Rasmusowi, Sashay oraz Richardowi Lynchowi za odpowiedzi na liście dyskusyjnej. Autorzy chcieliby móc podziękować za pomoc swoim małżonkom, ale niestety jest to w tej chwili niemożliwe. :)
Rzut oka na książkę O Autorach...............................................................................................................19 Przedmowa..............................................................................................................^!
Rozdział 3. Rozpoczynamy pracę z PHP....................................................................55 Rozdział 4. Dodajemy PHP do HTML.........................................................................69
Rozdział 5. Składnia, zmienne i wyświetlanie............................................................75 Rozdział 6. Typy w PHP ...........................................................................................91
Rozdział 7. Sterowanie ..........................................................................................111 Rozdział 8. Użycie i definiowanie funkcji ................................................................133 Rozdział 9. Ciągi i funkcje operujące na ciągach ....................................................155
Rozdział 10. Matematyka........................................................................................177 Rozdział 11. Tablice i funkcje operujące na tablicach ...............................................199 Rozdział 12. Przekazywanie danych pomiędzy stronami ............................................225 Rozdział 13. Funkcje systemu operacyjnego i dostępu do plików ..............................235 Rozdział 14. Styl PHP..............................................................................................251
Część II PHP i bazy danych ............................................................297 Rozdział 16. Wybór bazy danych dla PHP .................................................................299 Rozdział 17. Samouczek SQL...................................................................................311 Rozdział 18. Funkcje PHP i MySQL ..........................................................................325
Rozdział 19. Wyświetlanie zapytań w tabelach .........................................................337
Rozdział 23. Styl i efektywność rozwiązań na podstawie PHP i bazy danych ..............389 Rozdział 24. Pułapki tandemu PHP-baza danych .......................................................399
Część III Rozdział
Techniki zaawansowane....................................................411 25.
Rozdział 1. Dlaczego PHP? ......................................................................................29 Co to jest PHP?.......................................................................................................................29 Historia PHP......................................................... ................................................................. 30 Dlaczego kochamy PHP? ....................................................................................................... 31 PHP jest darmowy............................................................................................................ 31 PHP jest łatwy .................................................................................................................. 32 PHP można wbudować..................................................................................................... 33 PHP jest niezależny.......................................................................................................... 35 PHP nie bazuje na znacznikach........................................................................................ 35 PHP jest stabilny .............................................................................................................. 36 PHP jest szybki................................................................................................................. 36 PHP jest otwarty............................................................................................................... 37 PHP dobrze współpracuje z innymi produktami.............................................................. 38 Popularność PHP rośnie................................................................................................... 38 PHP nie jest niczyją własnością....................................................................................... 39 Społeczność PHP..............................................................................................................40 Podsumowanie........................................................................................................................ 40 Rozdział 2. Skrypty wykonywane na serwerze WWW.................................................41 Statyczny HTML.................................................................................................................... 41 Technologie wykonywane na kliencie.................................................................................... 44 Skrypty wykonywane na serwerze.......................................................................................... 47 Do czego są dobre skrypty serwera ........................................................................................ 51 Podsumowanie........................................................................................................................ 53 Rozdział 3.
Rozpoczynamy pracę z PHP....................................................................55 Dzierżawa lub własny serwer................................................................................................. 55 Wariant z dostawcąInternetu........................................................................................... 55 Własny serwer: wady i zalety........................................................................................... 58 Rozwiązania pośrednie..................................................................................................... 59 Instalowanie PHP................................................................................................................... 59 Zanim zaczniesz............................................................................................................... 60 Procedura instalacji.......................................................................................................... 61 Narzędzia programistyczne.............................................................................................. 66 Podsumowanie........................................................................................................................ 67
Dodajemy PHP do HTML.........................................................................69 HTML jest gotowy na PHP .................................................................................................... 69
Przełączanie się z HTML do PHP .......................................................................................... 70 Kanoniczne znaczniki PHP .............................................................................................. 70 Krótkie znaczniki otwierające (w stylu SGML)............................................................... 70 Witaj świecie.................................................................................................................... 71
Wejście i wyjście z trybu PHP ......................................................................................... 72 Dołączanie plików............................................................................................................ 73 Podsumowanie........................................................................................................................ 74
Rozdział 5.
Składnia, zmienne i wyświetlanie............................................................75
PHP wiele wybacza................................................................................................................ 75 HTML to nie PHP...................................................................................................................76 Składnia PHP bazuje na C...................................................................................................... 76 PHP nie przejmuje się odstępami..................................................................................... 76 PHP jest czasami wrażliwy na wielkość liter ................................................................... 77 Instrukcje to wyrażenia zakończone średnikiem .............................................................. 77 Bloki................................................................................................................................. 80 Komentarze ............................................................................................................................ 80 Komentarze wielowierszowe w stylu C ........................................................................... 81 Komentarze jednowierszowe: # i //.................................................................................. 81 Zmienne.................................................................................................................................. 82 PHP skorzystał ze stylu zmiennych Perl........................................................................... 82 Deklarowanie zmiennych................................................................................................. 82 Przypisywanie zmiennym wartości.................................................................................. 82 Zmiana wartości zmiennych............................................................................................. 83 Nieprzypisane zmienne.................................................................................................... 83 Możesz dowolnie zmieniać tryby pracy ........................................................................... 85 Wyjście................................................................................................................................... 86
Echo i print....................................................................................................................... 86 Zmienne i ciągi................................................................................................................. 87 Podsumowanie........................................................................................................................ 88
Rozdział 6.
Typy w PHP ...........................................................................................91 Pierwsza zasada: nie przejmuj się........................................................................................... 91
Brak deklaracji typów zmiennych.................................................................................... 91 Automatyczna konwersja typów ...................................................................................... 92 Typy w PHP ........................................................................................................................... 92 Typy proste............................................................................................................................. 93 Integer.............................................................................................................................. 93 Double..............................................................................................................................94 Boolean............................................................................................................................ 95 Przykłady.......................................................................................................................... 96 String................................................................................................................................ 97 Tablice.................................................................................................................................. 100 Implementacja tablic...................................................................................................... 101 Ciągi znaków jako indeksy tablicy................................................................................. 101 Czy w PHP są struktury?................................................................................................ 102 Inne własności tablic ...................................................................................................... 102 Obiekty................................................................................................................................. 102 Przegląd OOP................................................................................................................. 102 Jak bardzo obiektowy jest PHP? .................................................................................... 103
Definiowanie klas w PHP............................................................................................... 103 Tworzenie obiektów....................................................................................................... 104
Ciągi i funkcje operujące na ciągach ....................................................155 Ciągi w PHP ......................................................................................................................... 155 Znaki i indeksy ciągu ..................................................................................................... 156 Operatory dla ciągów ..................................................................................................... 156 Złączenie i przypisanie................................................................................................... 157 Funkcje operujące na ciągach............................................................................................... 157 Sprawdzanie ciągów....................................................................................................... 157 Szukanie znaków i podciągów ....................................................................................... 158 Porównywanie i przeszukiwanie .................................................................................... 159 Przeszukiwanie............................................................................................................... 160 Wycinanie podciągu....................................................................................................... 161 Funkcje porządkujące..................................................................................................... 163 Zastępowanie ciągów..................................................................................................... 163 Ciągi i kolekcje znaków ................................................................................................. 165 Funkcje analizujące........................................................................................................ 167 Funkcje zmiany wielkości liter....................................................................................... 169 Funkcje znaków sterujących........................................................................................... 170 Formatowanie danych.................................................................................................... 171 Zaawansowane własności ciągów......................................................................................... 173 Wyrażenia regularne....................................................................................................... 173 Funkcje HTML............................................................................................................... 176 Podsumowanie...................................................................................................................... 176
Typy numeryczne................................................................................................................. 177 Operatory matematyczne...................................................................................................... 178 Operatory arytmetyczne................................................................................................. 178 Operatory arytmetyczne i typy ....................................................................................... 178 Operator inkrementacji................................................................................................... 179 Operator przypisania...................................................................................................... 180 Operatory porównania.................................................................................................... 180 Kolejność operacji i nawiasy.......................................................................................... 181 Proste funkcje matematyczne ............................................................................................... 182 Konwersja podstawy............................................................................................................. 184 Funkcje wykładnicze i logarytmy......................................................................................... 186 Trygonometria...................................................................................................................... 186 Liczby losowe....................................................................................................................... 190 Inicjowanie generatora................................................................................................... 190 Przykład: losowy wybór................................................................................................. 192 Arytmetyka o dowolnej dokładności.................................................................................... 193 Przykład użycia funkcji o dowolnej dokładności........................................................... 194 Konwersja obliczeń na dowolną dokładność.................................................................. 195 Podsumowanie...................................................................................................................... 197
Rozdział 11.Tablice i funkcje operujące na tablicach...............................................199 Użycie tablic......................................................................................................................... 199 Czym są tablice PHP?........................................................................................................... 200 Tworzenie tablic................................................................................................................... 202 Bezpośrednie przypisanie............................................................................................... 202 Konstrukcja arrayQ......................................................................................................... 203 Podawanie indeksów przy użyciu arrayQ....................................................................... 203 Funkcje zwracające tablice............................................................................................. 204 Odczytywanie wartości......................................................................................................... 204 Konstrukcja list()............................................................................................................ 205
Informacje o tablicach .......................................................................................................... 207 Usuwanie z tablicy ............................................................................................................... 207 Iteracje.................................................................................................................................. 208 Użycie funkcji iteracyjnych............................................................................................ 208 Iteracje za pomocą currentQ i next().............................................................................. 210 Powtórne przeglądanie za pomocąreset()...................................................................... 2 1 1
Wypisywanie w odwrotnym porządku za pomocąend() i prev()................................... 212 Pobieranie wartości kluczy za pomocąkey().................................................................. 213 Wartości puste i funkcja each()...................................................................................... 213
Przeglądanie tablicy za pomocą array _walk()................................................................ 214 Stosy i kolejki....................................................................................................................... 215 Przekształcenia tablic ........................................................................................................... 218
Pobieranie kluczy i wartości........................................................................................... 218 Zamiana, odwracanie i mieszanie................................................................................... 219
Zamiana pomiędzy tablicąi zmiennymi............................................................................... 222 Sortowanie............................................................................................................................ 222
Rozdział 12. Przekazywanie danych pomiędzy stronami ............................................225 HTTP jest protokołem bezstanowym.................................................................................... 225 Argumenty GET................................................................................................................... 226 Inne zastosowania adresów URL w stylu GET..................................................................... 228 Argumenty POST................................................................................................................. 230 Zarządzanie zmiennymi w PHP............................................................................................ 232 Podsumowanie...................................................................................................................... 234
Rozdział 13. Funkcje systemu operacyjnego i dostępu do plików ..............................235 Funkcje czytania i zapisywania plików ................................................................................ 236
Otwarcie pliku................................................................................................................ 236 Czytanie
Funkcje systemu plików i katalogów.................................................................................... 241 feof.................................................................................................................................241 file_exists....................................................................................................................... 241 filesize............................................................................................................................ 244
Funkcje sieciowe.................................................................................................................. Funkcje logu systemowego ............................................................................................ Funkcje DNS.................................................................................................................. Funkcje gniazd............................................................................................................... Funkcje daty i czasu .............................................................................................................
244 244 244 245 245
Jeżeli nie znasz daty ani czasu........................................................................................ 246
Jeżeli już odczytałeś datę i czas...................................................................................... 247 Funkcje konwersji kalendarza .............................................................................................. 247
Pliki dołączane............................................................................................................... 260 Interfejs obiektowy......................................................................................................... 262 Solidność.............................................................................................................................. 263 Niedostępność usługi...................................................................................................... 263 Niespodziewany typ zmiennej........................................................................................ 263 Zwięzłość i wydajność.......................................................................................................... 264 Używaj właściwych algorytmów.................................................................................... 264 Poprawianie wydajności................................................................................................. 264 Zwięzłość: zmniejszanie................................................................................................. 265 Wskazówki na temat zwięzłości..................................................................................... 266 Tryb HTML, czy PHP? ........................................................................................................ 268 Oddzielanie kodu od projektu............................................................................................... 274 Funkcje........................................................................................................................... 274 Arkusze stylów w PHP................................................................................................... 274 Szablony i spójność stron............................................................................................... 275 Podsumowanie...................................................................................................................... 276
Rozdział 15. Podstawowe pułapki PHP.....................................................................277 Problemy związane z instalacją............................................................................................ 277
Źródło pliku wyświetlane w przeglądarce...................................................................... 278 Blok PHP pokazuje się jako tekst; przeglądarka chce zapisać plik ................................ 278 Nieodnaleziony serwer lub niemożliwe wyświetlenie strony......................................... 278 Problemy z wyświetlaniem................................................................................................... 279 Całkowicie pusta strona.................................................................................................. 279 Niekompletna lub nieprawidłowa strona........................................................................ 279 Kod PHP pokazuje się w przeglądarce........................................................................... 281 Niepowodzenie przy ładowaniu strony................................................................................. 282 Nieodnaleziona strona.................................................................................................... 282 Nieudane otwarcie pliku do włączenia........................................................................... 283 Błędy analizy składni............................................................................................................ 283 Komunikat błędu składni................................................................................................ 283 Brakujący średnik........................................................................................................... 284 Brak znaku $ .................................................................................................................. 284 Nieprawidłowa zmiana trybu.......................................................................................... 285 Nieoznaczone apostrofy................................................................................................. 285 Inne błędy składni.......................................................................................................... 286 Uprawnienia do plików......................................................................................................... 286 Błąd HTTP nr 403 .......................................................................................................... 286 Brak dołączanych plików ..................................................................................................... 286 Ostrzeżenie przy włączaniu pliku................................................................................... 287 Nieprzypisane zmienne......................................................................................................... 287 Zmienna nie pokazuje się w wynikowym ciągu............................................................. 287 Jak zachowują się niezainicjowane zmienne.................................................................. 288 Problemy z wielkością liter............................................................................................ 288 Problemy z zasięgiem..................................................................................................... 288 Problemy z funkcjami........................................................................................................... 289 Wywołanie niezdefiniowanej funkcji............................................................................. 289 Nie można ponownie zadeklarować funkcji................................................................... 290 Nieprawidłowa liczba argumentów................................................................................ 290 Błędy matematyczne............................................................................................................. 290 Ostrzeżenie o dzieleniu przez zero ................................................................................. 290 Niespodziewane wyniki działań..................................................................................... 291 NaN (lub NAŃ).............................................................................................................. 291
Przekroczenie czasu oczekiwania......................................................................................... 292 Podsumowanie...................................................................................................................... 292
Część II
PHP i bazy danych ............................................................297
Rozdział 16. Wybór bazy danych dla PHP .................................................................299
Czemu używamy baz danych?.............................................................................................. 299 Unikanie redundancji..................................................................................................... 300 Unikanie nudnego programowania................................................................................. 300 Szukanie......................................................................................................................... 300 Bezpieczeństwo.............................................................................................................. 301 Architektura wielowarstwowa........................................................................................ 301 Wybór bazy danych.............................................................................................................. 302 Możesz nie mieć wyboru................................................................................................ 302 Plikowe, relacyjne i obiektowo-relacyjne bazy danych.................................................. 302 ODBC/JDBC kontra własne API................................................................................... 303 Zmiana bazy danych....................................................................................................... 304 Przegląd zaawansowanych funkcji....................................................................................... 304 GUI.................................................................................................................................304 Podzapytania.................................................................................................................. 304 Złożone złączenia........................................................................................................... 305 Wielowątkowość i blokowanie....................................................................................... 305 Transakcje...................................................................................................................... 305 Procedury i wyzwalacze................................................................................................. 306 Klucze obce i więzy integralności.................................................................................. 306 Replikacja bazy danych.................................................................................................. 306 Bazy danych obsługiwane przez PHP................................................................................... 307 Wybieramy MySQL.............................................................................................................307 Podsumowanie...................................................................................................................... 308
Rozdział 17. Samouczek SQL...................................................................................311 Standardy SQL ..................................................................................................................... 311 Podstawowe wyrażenia SQL................................................................................................ 312 SELECT......................................................................................................................... 312 INSERT.......................................................................................................................... 315 UPDATE........................................................................................................................ 316 DELETE......................................................................................................................... 316 Projekt bazy danych.............................................................................................................. 316 Użycie połączeń do bazy danych.......................................................................................... 319 Bezpieczeństwo i uprawnienia.............................................................................................. 319 Ustawianie uprawnień.................................................................................................... 320 Przechowywanie haseł w innym miejscu ....................................................................... 320 Użycie formularzy PHP do sprawdzania haseł............................................................... 321 Tworzenie kopii bezpieczeństwa.................................................................................... 322 Podsumowanie...................................................................................................................... 322 Rozdział 18. Funkcje PHP i MySQL ..........................................................................325 Łączenie z MySQL............................................................................................................... 325 Tworzenie zapytań w MySQL.............................................................................................. 326 Pobieranie wyniku................................................................................................................ 327 Pobieranie opisu danych....................................................................................................... 330 Korzystanie z wielokrotnych połączeń................................................................................. 330 Kontrola błędów................................................................................................................... 332 Tworzenie baz danych MySQL za pomocą PHP.................................................................. 332
Funkcje MySQL................................................................................................................... 333 Podsumowanie...................................................................................................................... 335
Rozdział 19. Wyświetlanie zapytań w tabelach .........................................................337 Tabele HTML i tabele bazy danych...................................................................................... 338 Przekształcenie jeden w jeden........................................................................................ 338 Przykład: wyświetlanie jednej tabeli.............................................................................. 338 Przykładowe tabele......................................................................................................... 340 Ulepszanie wyświetlania................................................................................................ 341 Złożone odwzorowania......................................................................................................... 343 Wiele zapytań albo skomplikowane wyświetlanie ......................................................... 344 Użycie kilku zapytań...................................................................................................... 345 Przykład skomplikowanego wyświetlania...................................................................... 346 Tworzenie przykładowych tabel........................................................................................... 348 Podsumowanie...................................................................................................................... 350
Rozdział 20. Tworzenie formularzy z zapytań.............................................................351 Formularze HTML ............................................................................................................... 351
Samoprzetwarzanie............................................................................................................... 352 Obsługa formularzy.............................................................................................................. 353 Formularze zależne od zmiennych........................................................................................ 356 TEXT i TEXTAREA......................................................................................................356 CHECKBOX.................................................................................................................. 358 RADIO........................................................................................................................... 359 SELECT.........................................................................................................................359 Formularze zależne od zapytań............................................................................................. 361 Podsumowanie...................................................................................................................... 362
Wprowadzanie danych przez HTTP..................................................................................... 368 Dołączenie bazy danych....................................................................................................... 370 Możliwe rozszerzenia........................................................................................................... 375 Podsumowanie...................................................................................................................... 376 Rozdział
22. Sieciowe głosowanie............................................................................377 Zadania systemu................................................................................................................... 377 Cele systemu.................................................................................................................. 378 Struktura......................................................................................................................... 378 Obsługa bazy danych...................................................................................................... 379 Zbieranie głosów.................................................................................................................. 379 Wyświetlanie sumarycznych wyników................................................................................. 383 Nadużycia i skalowanie.................................................................................................. 387 Podsumowanie...................................................................................................................... 387
Rozdział 23. Styl i efektywność rozwiązań na podstawie PHP i bazy danych ..............389 Połączenia — ograniczanie i powtórne użycie ..................................................................... 390 Przykład nieprawidłowego użycia: jedno połączenie na wyrażenie ............................... 390
Kilka wyników nie wymaga kilku połączeń................................................................... 391 Trwałe połączenia........................................................................................................... 391 Przenoszenie pracy na serwer bazy danych.......................................................................... 392
Baza jest szybsza od ciebie............................................................................................. 392 Przykład nieprawidłowego użycia: pętla zamiast warunku ............................................ 393
Rozdział 24. Pułapki tandemu PHP-baza danych .......................................................399 Brak połączenia.................................................................................................................... 399 Problemy z uprawnieniami................................................................................................... 402 Nieoznaczone apostrofy........................................................................................................ 403 Nieprawidłowe zapytania SQL............................................................................................. 405 Pomyłki w nazwach........................................................................................................ 407 Pomyłki przy przecinkach.............................................................................................. 407 Ciągi nieotoczone apostrofami....................................................................................... 407
Niezainicjowane zmienne............................................................................................... 407 Zbyt mało danych, zbyt dużo danych ................................................................................... 408
Kontrola poprawności........................................................................................................... 409 Podsumowanie...................................................................................................................... 409
Część III Techniki zaawansowane....................................................^! Rozdział
25. Sesje...................................................................................................413 Czym są sesje?...................................................................................................................... 413
Co stanowi problem?...................................................................................................... 413 Dlaczego się tym zajmujemy?........................................................................................ 414 Alternatywy sesji ..................................................................................................................414 Adres IP.......................................................................................................................... 414 Ukryte zmienne.............................................................................................................. 415 Cookie............................................................................................................................ 416 Jak działają sesje w PHP....................................................................................................... 416 Uaktywnianie sesji w PHP ............................................................................................. 417 Rejestrowanie zmiennych w sesji................................................................................... 418 Gdzie są przechowywane dane?..................................................................................... 419 Funkcje obsługi sesji............................................................................................................ 420 Przykładowy kod sesji.......................................................................................................... 422 Zagadnienia konfiguracji...................................................................................................... 423 Pułapki i wykrywanie usterek............................................................................................... 423 Podsumowanie...................................................................................................................... 426
Rozdział 26. Cookie i HTTP......................................................................................427 Cookie.................................................................................................................................. 427 Funkcja setcookieQ........................................................................................................ 428 Przykłady........................................................................................................................ 428 Usuwanie cookie............................................................................................................ 430 Odczytywanie cookie..................................................................................................... 431 Zmienne GET, POST i cookie........................................................................................ 432 Pułapki
PHP jako koło zapasowe do JavaScript................................................................................ 444 JavaScript statyczny kontra dynamiczny.............................................................................. 445 Dynamiczna generacja formularzy................................................................................. 446
Przesyłanie danych z JavaScript do PHP........................................................................ 450 Podsumowanie...................................................................................................................... 452
Rozdział
28. E-mail..................................................................................................455 Informacje na temat architektury e-mail............................................................................... 455 Model systemu e-mail.................................................................................................... 456
Pobieranie poczty za pomocą PHP ....................................................................................... 460 Tworzenie przez zaniechanie.......................................................................................... 461 Tworzenie przez przykład .............................................................................................. 461 Tworzenie przez upiększanie.......................................................................................... 461
Wysyłanie poczty za pomocą PHP ....................................................................................... 462 Konfiguracja Windows................................................................................................... 462 Konfiguracja Unixa........................................................................................................ 462 Funkcja maił................................................................................................................... 462 Więcej na temat aplikacji pocztowych.................................................................................. 464 Wysyłanie poczty z formularza...................................................................................... 464 Wysyłanie poczty przy użyciu bazy danych................................................................... 466 Własna aplikacja pocztowa w PHP ................................................................................ 466 Podsumowanie...................................................................................................................... 468 Rozdział 29. PHP i XML...........................................................................................469 Co to jest XML?...................................................................................................................469 Praca z XML......................................................................................................................... 472 Dokumenty i DTD................................................................................................................ 472 Struktura DTD................................................................................................................474 Analizatory kontrolujące i nie kontrolujące poprawności.............................................. 476 DOM kontra SAX................................................................................................................. 477 SAX................................................................................................................................ 477 DOM..............................................................................................................................
478
Funkcje PHP dla DOM.........................................................................................................478 SAX................................................................................................................................ 480 Użycie SAX.................................................................................................................... 481 Opcje
Funkcje PHP dla SAX .......................................................................................................... 483 Przykładowa aplikacja SAX................................................................................................. 486 Pułapki i wyszukiwanie błędów ........................................................................................... 491 Podsumowanie...................................................................................................................... 492
Rozdział 30. Programowanie obiektowe w PHP ........................................................493 Jak dobre jest programowanie obiektowe?........................................................................... 494 Terminologia programowania obiektowego................................................................... 494 Obiekty, klasy i typy w PHP .......................................................................................... 495 Atrybuty ......................................................................................................................... 496
Funkcje........................................................................................................................... 496 Konstruktory .................................................................................................................. 497 Dziedziczenie................................................................................................................. 497 Przesłanianie .................................................................................................................. 498 Przeciążanie.................................................................................................................... 499 Zasięg............................................................................................................................. 499 Przypisywanie, aliasy i referencje .................................................................................. 500 Wyświetlanie i drukowanie obiektów ............................................................................ 502 Przeglądanie................................................................................................................... 503
Funkcje przeglądania typów i klas........................................................................................ 503 Serializacja obiektów............................................................................................................ 507 Zewnętrzne interfejsy: COM, Java i CORBA....................................................................... 508 COM i DCOM................................................................................................................509
O Autorach Tim Converse pisał oprogramowanie pomagające w wyborze szalików, odpowiadające na pytania na temat stacji kosmicznych, pobierające notowania giełdowe oraz symulujące robienie kolacji. Zdobył dyplom magistra informatyki na University of Chicago. Pracuje teraz w Excite@Home, gdzie zajmuje się wyszukiwarką internetową.
Joyce Park posiada dyplom magistra historii University of Chicago; pracowała nad kilkoma witrynami informacyjnymi w PHP, między innymi nagrodzoną MysteryGuide. com. Jej teksty zdobyły uznanie redaktorów oraz czytelników Slashdot, OSOpinion, Linux.com i wielu innych na całym świecie. Joyce jest teraz projektantem witryn w firmie Epinions.com.
20
PHP 4. Biblia
Przedmowa Witamy w książce P HP 4. Biblial Mimo że jesteśmy stronniczy, wierzymy, że PHP, skryptowy język programowania dla WWW, zajął niszę najłatwiejszego i najbardziej
elastycznego narzędzia dla serwerów WWW, pozwalając na tworzenie wspaniałych i bardzo szybkich witryn. Mimo że miliony programistów WWW na całym świecie zwykle mogą się mylić, w tym konkretnym przypadku nie mylą się.
PHP 4.0, udostępniony na wiosnę 2000 roku, został, w porównaniu do PHP 3, uzupełniony o wiele nowych możliwości, działa dużo szybciej. W książce tej przedstawione są główne możliwości tej wersji programu. Szczegółowe przykłady pokazują, w jaki sposób tworzyć witryny WWW przy użyciu PHP.
Co to jest PHP? PHP jest językiem skryptowym wbudowywanym w strony WWW, wykonywanym na serwerze. Jest on zgodny z większością najważniejszych serwerów WWW (najbardziej ze znakomitym Apache). PHP pozwala na wbudowanie fragmentów kodu w normalne strony HTML — kodu, który jest interpretowany, gdy strony są przesyłane do użytkownika. PHP spełnia rolę „kleju" ułatwiającego łączenie stron WWW z bazami danych umieszczonych po stronie serwera.
Dlaczego PHP? Odpowiedzi na to pytanie poświęcamy prawie cały rozdział l. Najkrótsza odpowiedź to: jest darmowy, ma duże możliwości, jest niezależny, stabilny, szybki, łatwy do nauki, dobrze zaprojektowany, dobrze współpracuje z innymi produktami. A poza tym mamy dostęp do kodu źródłowego.
Co nowego w PHP 4? PHP 4 zawiera wszystkie funkcje PHP oraz wbudowane wsparcie dla sesji, bardziej spójną analizę składni, nowy typ Boolean oraz wiele nowych funkcji. Rdzeniem maszyny skryptowej PHP jest teraz „Zend", który został napisany na nowo, aby zachować spójność oraz zyskać rewelacyjną szybkość działania. PHP to żywy organizm. Oryginalną wersję książki wydrukowano na wiosnę 2000 roku, mniej więcej w tym samym czasie, gdy PHP 4 został oficjalnie wydany. Przykłady zawarte w niej były intensywnie testowane za pomocą PHP 3 oraz różnych wersji beta PHP 4. Mimo, że opisaliśmy większość głównych funkcji PHP 4, wciąż pojawiają się nowe.
Dla kogo jest ta książka Książka jest przeznaczona dla każdego, kto chce tworzyć witryny WWW, bardziej złożone, niż pozwala HTML. Mamy szczególnie na myśli trzy grupy: * projektantów stron WWW, którzy znają HTML i chcą rozpocząć tworzenie dynamicznych witryn WWW; * zaawansowanych programistów (C, Java, Perl itp.), ale bez doświadczenia w projektowaniu dla WWW, którzy chcą szybko nabrać biegłości w programowaniu dla serwerów WWW; * programistów WWW, którzy używali innych technik programowania (np.: Active Server Pages, Java Server Pages, Cold Fusion) i chcą zmienić lub po prostu poznać inne narzędzie.
Zakładamy, że czytelnik zna język HTML i ma podstawową wiedzę na temat sposobu
działania Sieci, ale nie oczekujemy żadnego dodatkowego doświadczenia programistycznego. Aby zaoszczędzić czas bardziej zaawansowanym programistom, dodaliśmy wiele notatek i komentarzy porównujących PHP z innymi językami i wskazujących, które rozdziały i fragmenty mogą być przez nich pominięte. Na koniec przejrzyj nasze dodatki, które zawierają specyficzne porady dla programistów C, ASP oraz projektantów HTML.
Książka nie jest podręcznikiem Grupa dokumentalistów PHP przygotowała świetny podręcznik, pod adresem http:// www.php.net, udostępniany oczywiście przez PHP. Książka ta nie jest takim podręcznikiem, ani nawet jego namiastką. Uważamy ją za uzupełnienie podręcznika.
Podręcznik jest obszerny, obejmuje wszystkie aspekty i funkcje języka, jednak pozbawiony jest szczegółów. My, w przeciwieństwie, mamy możliwość skupienia się na tematach, które są najczęściej poruszane lub najmniej zrozumiałe, możemy wyjaśniać i dawać długie przykłady.
Jak zorganizowana jest książka Książka jest podzielona na trzy części:
Część l Podstawy Rozdziały od 1. do 4. stanowią wprowadzenie do PHP i opisują zagadnienia, które musisz poznać przed rozpoczęciem pracy. Rozdziały od 5. do 13. to przewodnik traktujący o głównych aspektach PHP (oprócz
współpracy z bazami danych): składni, typach danych, podstawowych funkcjach wbudowanych. Możesz opuścić ten fragment i używać go jak skorowidza. Rozdziały 14. i 15. to podręcznik stylu PHP oraz opis najczęściej spotykanych przy programowaniu pułapek.
Część II PHP i bazy danych Rozdziały 16. i 17. dają ogólną orientację na temat programowania dla WWW przy użyciu baz danych SQL. Znajdują się tutaj porady, w jaki sposób wybrać najlepszy
system baz danych.
Rozdział 18. poświęcony jest funkcjom PHP dla MySQL — systemu baz danych, który
będziemy omawiali aż do końca drugiej części książki.
Rozdziały od 19. do 22. to szczegółowe i bogate w przykłady analizy przypadków współpracy PHP z bazami danych. W rozdziałach 23. i 24. znajdują się wskazówki i opisy pułapek w pracy z PHP i bazami danych.
Część III Techniki zaawansowane W każdym z rozdziałów od 25. do 32. opisujemy bardziej zaawansowane, niezależne tematy. Omawiamy: nowe wbudowane funkcje obsługi sesji, użycie mechanizmu cookie, generowanie kodu Javascript, przyłączanie PHP do programów pocztowych, wsparcie dla XML, programowanie obiektowe, bezpieczeństwo i opcje konfiguracji.
Konwencje używane w książce Używamy czcionki o stałej szerokości do zaznaczenia literałów kodu PHP. Fragmenty
kodu zawarte w tekście wyglądają w następujący sposób, natomiast oddzielny fragment kodu wygląda tak: p r i n t ( " t a k "} ;
Jeżeli wygląd strony WWW wygenerowanej przez PHP jest ważny, zamieszczamy rysunek z kopią ekranu; gdy nie jest — zamieszczamy źródło strony wygenerowanej przez PHP przy użyciu czcionki o stałej szerokości. Jeżeli chcemy odróżnić wynik skryptu PHP widoczny w przeglądarce od aktualnego wyniku PHP (który tłumaczy
przeglądarka), nazywamy go „wynikiem z przeglądarki".
Jeżeli zaznaczamy fragment kodu kursywą, oznacza to, że to miejsce należy odpowiednio zmienić, a nie traktować tekst dosłownie. Jeżeli w normalnym tekście wyróżniamy wyraz za pomocą kursywy, oznacza to, że wyraz jest niezbyt znany i zdefiniowany w słowniku.
Znaczenie ikon Ikony, przedstawione poniżej, są rozrzucone w całym tekście. Ich zadaniem jest wyraź-
ne zaznaczenie wagi informacji.
Wskazówki oznaczają sztuczki lub techniki PHP, które nie są oczywiste, a mogą pozwolić na wykonanie jakiejś czynności łatwiej i efektywniej. Ikona notatki zwykle oznacza dodatkowe informacje lub wyjaśnienia, które jednak można zignorować, jeżeli nie wydają się interesujące. Notatki w tej książce są często kierowane do określonej grupy czytelników, którzy znają konkretny język programowania lub technologię. Ikona ostrzeżenia wskazuje coś, co może być niezrozumiałe lub źle użyte, i w efekcie może sprawiać programistom kłopoty.
Ikona nowej funkcji oznacza nową możliwość w PHP 4.
Używamy tej ikony, aby skierować czytelnika do pokrewnej informacji w innym rozdziale lub innej części książki.
Witryna WWW i przykłady kodu Wszystkie przykłady z tej książki znajdują się pod adresem:
ftp://ftp.helion.pl/przyklady/php4bi.zip Dodatkowe materiały znajdują się na stronie WWW pod adresem: http://w\vw. troutworks. com/phpbook
.26________________________________________
,.»»*».,„„,„ „„.„-u,*,
PHP 4. Biblia
Cześć l
Podstawy PHP
Rozdział 1.
Dlaczego PHP? W tym rozdziale:
+ Co to jest PHP? «• Historia PHP *• Dlaczego kochamy PHP?
* Wyprzedzamy konkurencję z PHP Pierwszy rozdział zawiera wprowadzenie do PHP. Spróbujemy odpowiedzieć tu na kilka często stawianych pytań na temat PHP, takich jak: „Co to jest" lub „Jakie jest w porównaniu do podobnych technologii". Większość rozdziału zajęło wymienianie powodów, dlaczego kochamy PHP. Jeżeli jesteś inżynierem szukającym argumentów, aby przekonać szefa lub pytających „co to jest to P-coś-tam", rozdział ten dostarczy podstawowych odpowiedzi.
Co to jest PHP? PHP pochodzi od Hypertext Preprocessor. Właściwie produkt ten wcześniej nazywał się Personal Home Page Tools, jednak gdy jego zakres rozszerzył się, w drodze głosowania została wybrana nowa, bardziej właściwa nazwa. Dla pliku PHP można używać dowolnego rozszerzenia, ale zalecane są .php, ,php3 oraz .phtml. Aktualnym numerem wersji PHP jest 4, nazywany PHP 4 lub po prostu PHP. PHP jest językiem skryptowym wbudowywanym w HTML, wykonywanym na serwerze. Inne produkty w tej niszy to: Active Server Pages Microsoftu, ColdFusion firmy Allaire oraz Java Server Pages — Sun. PHP jest czasami nazywany „darmowym ASP", ponieważ sposób jego działania jest bardzo podobny do produktu (koncepcji) Microsoftu. W następnym rozdziale prześledzimy dokładnie koncepcję skryptów wykonywanych na serwerze, a w tej chwili możesz myśleć o nich jak o zestawie znaczników superHTML,
30__________________________________________Część
l
»
Podstawy
PHP
które pozwalają dodać funkcje obsługi serwera do stron WWW. Możesz np. użyć PHP do tworzenia na bieżąco skomplikowanych stron WWW lub do uruchamiania programu do obciążania karty kredytowej, gdy klient złoży zamówienie. Ściśle mówiąc, PHP ma niewiele wspólnego z układem strony, zdarzeniami lub czymkolwiek innym, co nadaje wygląd stronom WWW. Właściwie wszystko, co robi PHP, jest
niewidoczne dla użytkownika. Ten, kto ogląda stronę PHP, nie jest w stanie powiedzieć,
że strona nie została napisana w HTML, ponieważ wynikiem PHP jest kod HTML.
PHP jest oficjalnym modułem do serwera HTTP Apache, który jest wiodącym, bezpłat-
nym serwerem WWW, napędzającym około 55% serwerów sieci. Oznacza to, że maszyna skryptowa PHP jest wbudowana w serwer WWW, co powoduje szybszą obsługę stron. Podobnie jak serwer Apache PHP jest niezależny od platformy, działa w kilku rodzajach systemu Unix oraz w Windows. Wszystkie projekty prowadzone przez Apache Software Foundation — włączając w to PHP — są dostępne na zasadzie open source (mamy dostęp do kodu źródłowego). Różne wersje PHP zebrały przez kilka lat wiele pochwał i nagród. PHP 3 był w 1999 r.
finalistą konkursu LinuxWorld Editor's Choice Awards (w kategorii biblioteka — narzędzie programistyczne), w 1998 r. wygrał z ColdFusion CNet Builder.com Product Awards (w kategorii najlepsze narzędzie skryptowe). Kombinacja PHP 3/MySQL wygrała w konkursie Database of the Year na Web '98. Nieźle, jak na program bez działu PR, bez reklam i bez agencji reklamowej.
Historia PHP Rasmus Lerdorf— programista, członek zespołu Apache —jest twórcą i siłą napędową PHP. Pierwszą część PHP napisał na własny użytek w 1994 roku. Był to interfejs Perl CGI, który pomagał śledzić, kto odwiedza stronę domową. W następnym roku, w odpowiedzi na żądania użytkowników, którzy zaangażowali się w ten projekt, skompleto-
wał pakiet nazwany Personal Home Page Tools (znany również jako PHP Construction
Kit). Niebawem została wydana wersja 2. o nazwie PHP/FI, zawierająca Form Interpreter, narzędzie do przetwarzania zapytań SQL.
W połowie 1997 r. około witryn na całym świecie 50 000 używało PHP. Obsługa przekroczyła możliwości jednej osoby, nawet tak energicznej jak Rasmus. Niewielki zespół programistów rozpoczął projekt na zasadzie open source, korzystając z pomocy programistów i użytkowników z całego świata. Dwóch izraelskich programistów, Zeev Suraski i Andi Gutmans (autorów analizatora składni do PHP 3 oraz PHP 4), rozszerza i uogólnia go pod szyldem Zend.com (od ich imion, Zeev i Andi).
W czwartym kwartale 1998 r. nastąpił gwałtowny rozwój PHP, który korzystając z za-
sady open source cieszył się masowym zainteresowaniem. W październiku 1998 r. około 100 000 różnych domen używało w jakiś sposób PHP. Rok później przełamana została bariera l 000 000 domen. W czasie pisaliśmy tę książkę, liczba ta eksplodowała do około dwóch milionów.
Dlaczego kochamy PHP? Jest wiele powodów, dla których kochamy PHP. W tym rozdziale poznasz niektóre z nich.
PHP jest darmowy PHP nic nie kosztuje. Nic na początku, nic w trakcie pracy aplikacji. Czy wspominaliśmy, że zestaw Apache+PHP+MySQL działa świetnie na niezbyt mocnym, tanim sprzęcie, w przypadku którego nawet nie możesz myśleć o instalacji IIS+ASP+SQL Server?
Dla porównania w tabeli 1.1 zamieściliśmy średnie ceny detaliczne podobnych produktów. Tabela 1.1.
Porównanie wydatków
Pozycja
ASP
ColdFusion
JSP
PHP
Tworzenie
0 - 2 000 zł
~1 500 zł
Ozł
Ozł
Serwer
2 500 zł
~5 000 zł
0 - 2 200 zł
Ozł
RDBMS
5 000 - 20 000 zł
0 - 4 0 000 zł
40 000 zł
Ozł
Wsparcie
0 - 1 000 zł
300 zł
300 zł
Ozł
Oprogramowanie open source: nie bój się taniego W zasadzie można by mieć wątpliwości na temat jakości i żywotności bezpłatnego
oprogramowania. Prawdopodobnie do tej opinii przyczyniło się oprogramowanie, za które nie trzeba płacić, zwane freeware, shareware lub Free Software, postrzegane jako należące do jednej z trzech kategorii: * programy wypełniające małe niekomercyjne nisze; 4 programy wykonujące ciężkie niskopoziomowe zadania;
+ programy dla ludzi o dziwnych poglądach socjo-politycznych. Czas na zmianę niektórych stereotypów. Jesteśmy w trakcie zmian w przemyśle tworzenia programów. Wiele (jeżeli nie większość) głównych programów dla konsumentów jest dziś rozprowadzanych bez opłat: programy pocztowe, przeglądarki WWW, gry,
czy nawet pełne pakiety biurowe są rozdawane tak szybko, jak tylko ich twórcy potrafią utworzyć wersję WWW lub ustawić serwer FTP. Oprogramowanie konsumenckie jest
coraz częściej postrzegane jako źródło strat, jak kolorowy kwiatek przyciągający
pszczoły — innymi słowy, sposób na sprzedanie większej liczby serwerów, systemów operacyjnych, połączeń, reklam lub akcji. Przez to cena programu nie odzwierciedla jego jakości.
32__________________________________________Część l
»
Podstawy PHP
W świecie serwerów idea open source oddziały wuj e jeszcze silniej. Takie produkty nie tylko konkurują z komercyjnymi, ale wydaje się, że są poza konkurencją. Nie musisz nam wierzyć! Jeżeli nie jesteś przekonany, więcej dowiesz się na witrynach: http://www. opensource. org
http://www.fsf.org
Licencja PHP Schemat licencjonowania typu open source i Free Software gwarantuje, że program jest bezpłatny. Schemat ten jest najbardziej znany pod nazwą GPL (Gnu General Public License) lub „copyleft". PHP był rozprowadzany na zasadach licencji GPL i własnej — do wyboru przez każdego użytkownika. Ostatnio jednak całość programu rozprowadzana jest na podstawie liberalnej licencji PHP 4, a Zend, jako osobny produkt, jest dystrybuowany na zasadach licencji Q Public license (klauzula jest stosowana, gdy Zend zostanie oddzielony od PHP i ktoś będzie chciał go sprzedawać).
Dokładne objaśnienie warunków obu licencji można przeczytać pod adresami: http://www.php. net/license
http://www. troll, no/ąpl/annotated. html Większość użytkowników może bezpłatnie ściągnąć PHP, niektórzy zapłacą za niego, jeżeli wchodzi w skład dystrybucji Linuksa, książki lub innego produktu. W takim wypadku pewnie będziesz miał mieszane uczucia na temat naszych zapewnień, że PHP nic nie kosztuje. Możemy to wytłumaczyć: mimo że nie musisz płacić za większość programów typu open source, zapłacisz za dostarczenie oprogramowania w bardziej wygodnej postaci — nagranej na dysk i dostarczonej do klienta. Możesz również zarabiać na dostarczaniu usług biorąc ryzyko, jakiego nie podejmuje zespół programistów PHP. Na przykład zagwarantujesz, że każda kopia będzie pozbawiona wirusów lub będzie odpowiedniej jakości, podejmując ryzyko pozwania przez klientów, którzy dostali uszkodzone CD-ROM-y. Zwykle użytkownicy programów open source mogą wybrać optymalną wersję spośród różnych propozycji: bezpłatnie i bez gwarancji, drogie, ale z świetnym serwisem lub coś pomiędzy. Nie ma jeszcze zorganizowanego serwisu ani wsparcia dla PHP (przypuszczalnie będzie to jeden z dodatków do Zend).
PHP jest łatwy PHP jest łatwy do nauczenia się, w porównaniu do innych produktów. W przeciwieństwie do Java Server Pages lub CGI opartego na języku C, PHP nie wymaga osiągnięcia biegłości w podstawowych językach programowania do napisania prostych odwołań do bazy danych. W przeciwieństwie do składni języka Perl, który jest żartobliwie nazywa-
ny językiem „tylko do zapisu", składnia PHP jest prosta do analizy i łatwa do zrozumienia przez programistę. W przeciwieństwie do Active Server Pages, PHP nie zmusza do uczenia się dwóch różnych języków!
Istnieje wiele predefmiowanych, bardzo użytecznych, a specyficznych funkcji (jak funkcje służące do łączenia się z bazami Oracle lub pobierania poczty z serwera IMAP).
Dostępnych jest również wiele gotowych skryptów, do których możesz zajrzeć w trak-
cie nauki PHP. Właściwie używanie PHP jest możliwe dzięki zmianom w istniejących skryptach bez potrzeby pisania od początku. Oczywiście musisz znać podstawowe zasady, ale możesz uniknąć wielu frustrujących i zabierających czas pomyłek. Musimy jednak ostrzec: „łatwy" może oznaczać co innego dla różnych użytkowników. Dla niektórych projektantów WWW oznac/a środowisko graficzne, używające technik „przenieś i upuść" lub „dostaniesz, co widzisz". Aby być naprawdę wydajnym, musisz umieć ręcznie tworzyć strony HTML. Można oczywiście używać narzędzi WYSIWYG do zaprojektowania witryny, sformatowania stron i dodania interakcji z użytkownikiem przed dodaniem kodu PHP do źródeł. Są również sposoby, które opisujemy w rozdziale
3., pozwalające dodać funkcje PHP do ulubionego środowiska projektowania. Jednak nie można w pełni korzystać z możliwości PHP bez patrzenia na kod źródłowy. Większość zaawansowanych użytkowników PHP (włączając w to członków zespołu tworzącego) to „zatwardziali koderzy". Twierdzą np., że ręcznie pisany kod jest piękny, czysty i maksymalnie zgodny z przeglądarką i dlatego jest jedynie słuszny — nie wahają się gwałtownie tego wyrażać. Społeczność PHP zapewnia pomoc i wymienia się
tajnikami języka przeważnie za pośrednictwem poczty elektronicznej, więc jeśli chcesz z nich skorzystać, musisz umieć czytać czysty kod źródłowy. Niektórzy użytkownicy narzędzi WYSIWYG czasami proszą członków listy dyskusyjnej o pomoc w rozpoznaniu problemu, ale obejrzeli stronę zamiast kodu źródłowego.
Powtórzmy jeszcze raz, że PHP jest łatwy. Jest tylko nieco bardziej wymagający niż HTML, ale chyba łatwiejszy niż JavaScript czy ASP i dużo mniej złożony koncepcyjnie
niż JSP.
PHP można wbudować PHP można wbudować w HTML. Inaczej mówiąc, strony PHP są zwykłymi stronami
HTML, które „przełączają się" w tryb PHP tylko, gdy jest to konieczne. Popatrzmy na przykład:
Powitanie
Cześć,
/* Przełączamy się w tryb PHP.
Zamiast zmiennych, w następnych trzech liniach można łatwo użyć danych z bazy danych*/ $firstname="Mata";
$lastname="Hari";
Stitle = "Ms.";
PRINT("$title Slastname"); // wracamy do HTML
?>.
Czy mogę nazywać cię ?
34__________________________________________Część l
»
Podstawy PHP
Gdy klient zażąda tej strony, serwer WWW przetworzy ją. Oznacza to, że przejrzy ją od początku do końca, szukając sekcji PHP, które spróbuje przetworzyć. Analizator składni pobierze wszystkie przypisane zmienne (oznaczone znakiem $) i spróbuje wstawić je do późniejszych wyrażeń (w tym przypadku do funkcji print ( ) ) . Jeżeli wszystko się uda, preprocesor zwróci normalną stronę WWW do przeglądarki klienta (rysunek 1.1). Rysunek 1.1.
Wynik przetworzonego PHP
Jeżeli zerkniesz do kodu źródła strony w przeglądarce, powinieneś zobaczyć coś takiego:
Powitanie
Cześć, Ms. Hari. Czy mogę nazywać cię Mata?
Gdybyś napisał to sam, byłoby identycznie. Proste!
Możliwość wbudowania PHP w HTML ma wiele pozytywnych konsekwencji: * PHP może być szybko dodany do kodu utworzonego przez edytory WYSIWYG. * PHP pomaga podzielić pracę pomiędzy projektantów i skryptowców. * Nie ma potrzeby przepisywania HTML w języku programowania. * PHP obniża koszty pracy i zwiększa wydajność.
Brak kompilacji Prawdopodobnie najlepszą rzeczą w językach skryptowych jest to, że nie muszą być kompilowane do postaci binarnej przed ich testowaniem i użyciem — po prostu napisz i uruchom. PHP jest interpretowany (jak prawie wszystkie najnowsze języki programowania), jednak Zend wykonuje czasami ukrytą prekompilację do zwiększenia szybkości działania skryptów.
A może potrzebujesz kompilacji? Może być ona użyteczna, gdy chcesz rozprowadzać kod w postaci binarnej tak, aby inni mogą go używać nie mając dostępu do źródła. Zespół Zend pracuje nad kompilatorem, który na to pozwoli, usprawniając przy tym duże i skomplikowane skrypty PHP.
PHP jest niezależny PHP działa na różnych popularnych rodzajach Uniksa i Windows. Większość serwerów HTTP na świecie działa na jednym z tych dwóch rodzajów systemów operacyjnych. PHP jest zgodny z trzema wiodącymi serwerami WWW: Apache HTTP Server dla
Unix i Windows, Microsoft Internet Information Server oraz Netscape Enterprise Server
(znanym również jako iPlanet Server). Działa również z mniej znanymi serwerami, jak np.: Alex Belits fhttpd, Microsoft Personal Web Server, AOLServer oraz Omnicentrix Omniserver. Nie działa na platformie Macintosh. Podstawowe kombinacje OS i serwera WWW są pokazane w tabeli 1.2. Tabela 1.2. Systemy operacyjne i serwery WWW dla PHP
Rodzaj
Unix
Windows
AIX, A/UX, BSDI, Digital UNIX/Tru64, FreeBSD, HP-UX, IRIX, Linux, NetBSD,
Windows 95, Windows 98, Windows NT, Windows 2000
Apache, fhttpd, Netscape
US, PWS, Netscape, Apache, Omni
OpenBSD, SCO UnixWare, Solaris, SunOS, Ultrix, Xenix i inne
Serwer WWW
Mimo że PHP nie działa jeszcze na Macintoshu, BeOS lub innych platformach, możesz projektować w tych systemach za pomocą ulubionego narzędzia, a następnie wrzucić skrypt PHP na serwer Unix lub Windows. Przedyskutujemy dokładnie ten proces
w rozdziale 3.
PHP nie bazuje na znacznikach PHP jest prawdziwym językiem programowania. W przeciwieństwie do niego ColdFusion jest zbiorem predefiniowanych znaczników podobnych do HTML. W PHP możesz zdefiniować dowolną funkcję, wpisując jej nazwę i definicję. W ColdFusion musisz użyć znaczników zdefiniowanych przez innych lub przebić się przez Custom Tag Extension. Dowcipny członek społeczności PHP powiedział: „W ColdFusion łatwe rzeczy robi się
łatwo, średnio trudne są niemożliwe". Każdy programista może to potwierdzić; gdy poznasz siłę nawiasów i pętli, nigdy nie wrócisz do znaczników.
36__________________________________________Część l »
Podstawy PHP
PHP jest stabilny Słowo „stabilny" oznacza w tym kontekście, że: 1. Serwera nie trzeba często restartować.
2. Wersje programu nie zmieniają się radykalnie i są ze sobą zgodne. W przypadku PHP zachodzą oba te przypadki. Serwer Apache jest jednym z najbardziej stabilnych serwerów WWW, działających długo bez przerw. Mimo że nie jest najszybszy, ani też najłatwiejszy do administrowa-
nia, po ustawieniu praktycznie nie przestaje działać. Nie wymaga również ponownego uruchomienia po każdej zmianie parametrów (przynajmniej wersja Uniksa). PHP korzy-
sta z tej niezawodności, dodatkowo jego konstrukcja jest solidna i wydajna. W dwuipółmiesięcznym teście przeprowadzonym w październiku 1999 r. przez laboratoria Network Computing serwer Apache razem z PHP z łatwością pokonał US i Visual Studio oraz Netscape Enterprise Server i Java w konkurencji stabilność środowiska. PHP jest również stabilny w sensie stabilności funkcji. Zespół projektantów jest bardziej zainteresowany jasną wizją projektu, a nie spełnianiem nieprzemyślanych zachcianek przypadkowych klientów. Większość pracy koncentruje się na ulepszeniach, na przykład przyspieszeniu analizatora czy lepszej obsłudze sesji. Bardzo niewiele funkcji zostało usuniętych przy zmianach wersji PHP.
PHP jest szybki PHP jest bardzo szybki w działaniu, szczególnie gdy jest skompilowany jako moduł serwera Apache działającego na Uniksie. W chwili obecnej PHP 4 jest dużo szybszy niż jakikolwiek skrypt CGI. Niestety prawdziwy jest żart, że CGI to skrót od „Can't Go Instantly" (nie może działać bez przerwy). Mimo że wiele ze skryptów CGI jest napisanych w C, jednym z najszybszych języków
programowania, szybkość jest ograniczana obsługą każdego żądania przez nowy proces uruchamiany przez serwer http. Czas oraz zasoby potrzebne na utworzenie i zakończenie procesu są znaczne, a system może ograniczać liczbę procesów działających jednocześnie. Inne skrypty CGI mogą być napisane w Perl lub Tcl i dlatego stosunkowo powolne. Większość witryn WWW odchodzi od stosowania skryptów CGI, aby polepszyć wydajność i zwiększyć bezpieczeństwo.
Mimo że PHP traci nieco na wydajności, ponieważ jest interpretowany, a nie kompilowany, równoważy to działaniem jako moduł serwera. Ponieważ nie ma komunikacji pomiędzy osobnymi aplikacjami (jak w ColdFusion), żądania są przetwarzane dużo szybciej. Pomimo braku formalnych obszernych testów wydajnościowych, które porównywałyby dwóch największych konkurentów, wiele eksperymentów i niewielkich testów pokazuje, że w większości aplikacji PHP jest co najmniej tak szybki jak ASP (więcej informacji można znaleźć na serwerze Zend.com).
PHP jest otwarty Zajmowaliśmy się już korzyściami finansowymi płynącymi z używania oprogramowania open source. Programy tego typu udostępniane są z pełnym kodem źródłowym. Wersja PHP dla Uniksa jest dostarczana tylko jako kod źródłowy, dlatego zespół programistów PHP nie musi rozprowadzać wersji skompilowanej dla każdego rodzaju Uniksa. Z początku nowi użytkownicy (szczególnie ci, którzy terminują w Uniksie) stwierdzają, że kod źródłowy jest równie użyteczny co piąte koło u wozu; większość z nich woli miłe i wygodne pliki rpm. Istniejąjednak idealistyczne i pragmatyczne powody zamiesz-
czania katalogów pełnych plików . c i .h. Pierwszą z zalet takiego rozwiązania jest to, że możesz skompilować instalację PHP zawierającą tylko te elementy, których naprawdę potrzebujesz. Podejście to pozwala na zwiększenie szybkości działania i poziomu bezpieczeństwa. Możesz dodać połączenia tylko do tych baz danych, których będziesz używał. Możesz kompilować PHP na nowo tak często, jak tylko zechcesz: gdy dostaniesz uaktualnienie zabezpieczeń do serwera Apache lub stwierdzisz, że potrzebujesz obsługi XML. To, co odróżnia oprogramowanie open source od konkurentów, to nie tylko cena, ale także kontrola. Większość oprogramowania użytkowego jest obecnie rozdawana pod
różnymi warunkami. Dokładne przeczytanie licencji odkryje ograniczenia sposobu, w jaki program może być używany. Być może dopuszczalne będzie korzystanie z niego tylko w domu, a nie w biurze. Możliwe, że będziesz mógł zainstalować go w twoim laptopie, ale złamiesz umowę, wykorzystując program do celów zawodowych. Zwykle można używać program w dowolny sposób, ale nie można obejrzeć kodu źródłowego, a tym bardziej go zmieniać. Istnieją nawet „licencje grupowe" nakładające na użytkowników warunek oddawania właścicielowi programu swoich pomysłów na ulepszenie, chociaż używanie jest płatne! Nawet nie myśl o łamaniu licencji oprogramowania. Szczególnie dziś, gdy bezpłatne oprogramowanie święci triumfy, nie ma powodu, aby łamać prawo.
W tabeli 1.3 zestawiliśmy różne sposoby kontroli źródeł i opłat na dzisiejszym rynku oprogramowania. Tabela 1.3. Różne metody opłat i kontroli źródel
Źródła kontrolowane
Źródła otwarte
Corel WorPerfect
Sun Java
MySQL
Microsoft IE
Sun StarOffice
Oprogramowanie GPL
Struktura opłat
Źródła prywatne
Opłaty od wszystkich użytkowników
Alaire ColdFusion
Opłaty od niektórych użytkowników Brak opłat
38_______________________________________Część l »
Podstawy PHP
Prawdziwe programy open source, jak PHP, mogą być wykorzystywane do wszelkich zastosowań. Znamiennym dowodem tego jest możliwość wprowadzania zmian i upowszechnianie ich razem z oryginalnym programem. Skrajne przypadki określane są mianem „rozwidlania kodu". Oznacza to, że jeżeli stworzysz zmiany niezgodne z propozycjami zespołu programistów PHP, możesz zabrać cały kod napisany do tej pory i wykorzystać go jako podstawę własnego produktu. Nie musisz nazywać go PHP, ale do dokumentacji musisz dołączyć informacje o autorach. Użytkownicy rozpoczynający przygodę z modelem open source powinni zdawać sobie sprawę, że prawo takie przynależy również twórcom. W każdej chwili Rasmus wraz z kolegami może opuścić społeczność i rozpocząć pracę nad komercyjnym produktem na bazie PHP. Oczywiście kod napisany do tej chwili będzie nadal dostępny i każdy (a powinna to być duża grupa programistów) może podjąć się kontynuacji projektu. Sytuacja taka przywodzi na myśl inną, często zapominaną zaletę oprogramowania open source: możesz być pewien, że oprogramowanie będzie w obiegu przez ładnych kilka lat. W dzisiejszych czasach trudno jest wybrać produkt utrzymujący się na szczycie
przez dłuższy czas. Wielbiciele OS/2, Amigi, NeXT, Newton, Firefly, Netscape znają uczucie osamotnienia, kiedy firma decyduje się zaprzestać wspierania technologii lub sprzedaje ją innej firmie. My również zostaliśmy uwiedzeni i porzuceni przez inny (teraz przestarzały) język skryptowy. Model open source zmniejsza możliwość porzucenia projektu i pozwala na bardziej realistyczne, długoterminowe planowanie.
PHP dobrze współpracuje z innymi produktami PHP ułatwia komunikację z innymi programami i protokołami. Zespół PHP próbuje zapewnić możliwie dużą elastyczność możliwie dużej grupie użytkowników. Łącza do baz danych są silną stroną PHP. Zapewniają funkcje obsługi około 15 popular-
nych baz danych oraz ODBC. PHP obsługuje dodatkowo kilka popularnych protokołów, np.: POP3, IMAP oraz LDAP, a także języka Java oraz rozproszonej architektury obiektowej (COM i CORBA), co umożliwia tworzenie programów o wielowarstwowej architekturze Większość produktów, których nie obsługuje PHP, ma zamkniętą architekturę. Apple Computer i Microsoft nie zgadzają się na współpracę w projektach typu open source.
Potencjalni użytkownicy, którzy narzekają na listach dyskusyjnych na brak obsługi
komputerów Mac lub SQL Server, nie są po prostu poinformowani, gdzie leży źródło
problemów.
Popularność PHP rośnie PHP staje się jednym z najbardziej popularnych narzędzi do tworzenia aplikacji dwuwarstwowych (WWW i dane). Rysunek 1.2 pokazuje rozwój jego popularności od początku 1999 r.
Rozdział
1.
»
Dlaczego
PHP?_______________________________________39
Rysunek 1.2.
Pomiar popularności
PHP (program Netcraft)
Jak można zauważyć, pomiędzy październikiem 1999 a październikiem 2000 zanotowano
wzrost liczby domen o 400%. Witryny WWW stają się wszechobecne i wiele z nich
wykracza poza zwykłe statyczne strony HTML. Dlatego spodziewamy się szybkiego wzrostu liczby użytkowników PHP.
Mimo że trudno jest uzyskać odpowiednie wykresy, wydaje się, że PHP stoi na mocnej pozycji w porównaniu do podobnych produktów. Technologia ASP firmy Microsoft jest używana w około 12% serwerów WWW, ColdFusion około 4%, natomiast z PHP korzysta 12% serwerów. Active Server Pages i ColdFusion są bardziej widoczne, ponieważ są wybierane przez duże witryny handlu elektronicznego. Jednak ogromna większość witryn WWW ma charakter informacyjny, a nie handlowy i z tego powodu nie zwraca w widoczny sposób
poniesionych nakładów finansowych. PHP ma wyraźną przewagę w tej kategorii.
PHP nie jest niczyją własnością Historia przemyski komputerowego jest kroniką standardów firmowych: prób ich ustanowienia, starć pomiędzy nimi, ich wad i zalet oraz sposobów, w jaki zostały zastąpione przez inne standardy. Od kilku lat Internet przekonuje o wygodzie bezpłatnych, zestandaryzowanych i niezależnych rozwiązań. E-mail działa tak dobrze, ponieważ korzysta z jasnego i stałego standardu, który musi być zachowany na każdej platformie. Nowe rozwiązania, które łamią standardy (przykładowo e-mail oparty o HTML), są uważane za odchylenie, a ich użytkownicy muszą zmagać się z ograniczeniami nieprzemyślanej technologii.
^0__________________________________________Część l
»
Podstawy PHP
W chwili obecnej projektanci oprogramowania zawieszeni są pomiędzy zmiennymi technologiami firmowymi a otwartymi standardami. Firmy chcą mieć pewność, że mogą utrzymać obrót, używając otwartych standardów. PHP jest bardzo elastyczny, ponieważ jest „afirmowy". Nie jest związany z żadnym
serwerem ani systemem operacyjnym, w przeciwieństwie do Active Server Pages. Nie jest też związany z żadnym przenośnym standardem lub warstwą pośrednią, jak Java Server Pages lub ColdFusion, ani też z przeglądarką, językiem programowania lub bazą danych. PHP narzuca też warunku pracy z innym oprogramowaniem.
Społeczność PHP PHP jest stworzony i wspierany przez światową społeczność użytkowników. Jednak „niektóre zwierzęta (główni programiści) są równiejsze od innych" — trudno się o to
spierać, ponieważ włożyli najwięcej pracy, mieli najlepsze pomysły oraz utrzymywali kontakty z największą liczbą innych użytkowników. Dla nowych użytkowników główną korzyścią jest bezpłatne wsparcie techniczne, bez granic i pokrętnych odpowiedzi. Użytkownicy, na listach dyskusyjnych przez 24 godziny na dobę i 7 dni w tygodniu, odpowiadają na pytania, pomagaj ą usunąć błędy i wysłuchuj ą narzekań. Członkowie społeczności mogą odesłać do podręcznika, zadać pytanie
na właściwej liście dyskusyjnej lub powstrzymać twoje jęki — nigdy nie zaproponują sformatowania dysku C i nie zażądają pieniędzy za usługę. Mogą zajrzeć do twojego
kodu źródłowego i wskazać źródło błędu lub nawet pomóc zaprojektować aplikację od podstaw. Gdy lepiej poznasz PHP, będziesz mógł się odwdzięczyć. Szukanie błędów, pomoc innym, wysyłanie skryptów do publicznych archiwów, tworzenie dokumentacji lub pisanie kodu w C i C++, oto kilka sposobów na spłacenie długu.
Podsumowanie Mimo że PHP posiada wiele zalet, nie jest panaceum na wszystkie problemy programistów WWW. Został stworzony przez programistów dla programistów i jest wspierany przez olbrzymią społeczność. Jego główne zalety to: lekkość, siła, pewność i łatwość użycia. Zapewnia możliwość podłączenia do olbrzymiej ilości różnych typów serwerów usługowych. W dodatku za darmo.
Rozdział 2.
Skrypty wykonywane na serwerze WWW W tym rozdziale:
* Statyczne i dynamiczne strony WWW 4 Skrypty wykonywane na kliencie i na serwerze * Wprowadzenie do skryptów wykonywanych na serwerze Rozdział ten zawiera informacje o skryptach wykonywanych na serwerze i ich związ-
kach z statycznymi stronami HTML oraz głównymi technologiami używanymi po stronie klienta. Przekazuje wiedzę na temat oferowanych przez PHP funkcji i sposobu, w jaki współpracuje z kodem klienta.
Statyczny HTML Podstawowym typem stron WWW są tekstowe strony napisane od podstaw w kodzie HTML. Przykład takiej strony jest pokazany na rysunku 2.1.
Źródło strony z rysunku 2.1.
KTITLE>Książki o sprzęcie komputerowym
Książki o przemyśle sprzętu komputerowego
Apple Computer
A p p l e < / A > : C a r l t o n , Jim ( 1 9 9 7 )
Insanely G r e a t < / A > :
Levy, Steveri (1993)
42__________________________________________Część
l
»
Podstawy
PHP
Rysunek 2.1.
Przykład
statycznego HTML
O d y s s e y : Pepsi to
Apple: Sculley, John (1997) Steve Jobs and the
NeXT Big Thing: Stross, Randall (1993)
Dell Computer
Direct from D e l l < / A >
: Dell, Michael (1999)
Intel
Only the Paranoid Survive: Grove, Andrew S. (1996) I n s i d e I n t e K / A > : Jacksvn, T i m ( 1 9 9 7 )
Sun Microsystems
H i g h Noon: Southwick, Karen ( 1 9 9 9 )
Gdy komputer klienta zażąda tej strony z serwera poprzez Internet lub Intranet w sposób pokazany na rysunku 2.2, serwer po prostu wyśle tekst strony do klienta. Gdy dane wracają do komputera klienta, przeglądarka rysuje stronę interpretując kod, biorąc pod uwagę ustawienia użytkownika, rozmiar monitora i inne czynniki. Zawartość pliku HTML na serwerze jest dokładnie taka sama, jak źródło strony na komputerze klienta.
Czysty, statyczny kod HTML posiada następujące zalety: * Każda przeglądarka wyświetli go poprawnie.
* Wiele urządzeń może go poprawnie wyświetlić. * Każde żądanie jest wykonywane szybko, przy użyciu niewielkich zasobów.
Rozdział 2.
» Skrypty wykonywane na serwerze WWW_______________________43
Rysunek 2.2. Proste żądanie HTTP
* HTML jest łatwy do nauczenia lub automatycznego wygenerowania. * Można szybko wprowadzić małe zmiany na pojedynczych stronach. Oczywiście statyczny kod HTML posiada również ograniczenia: * Trudno kontrolować układ strony.
+ Nie skaluje się prawidłowo. + Nie jest interaktywny.
4 Utrudnia wprowadzanie znaczących metadanych. * Nie radzi sobie z szybko zmieniającymi się danymi i personalizacją stron. * Nie jest zbyt atrakcyjny. Z tych powodów statyczny HTML staje się wyznacznikiem amatorszczyzny lub rygorów ideologicznych. Kilka technologii radzi sobie z tymi ograniczeniami. Należą do nich JavaScript, Cascading Style Sheet i aplety Java na końcówkach klienta oraz skrypty i połączenie z bazą danych po stronie serwera. Pojawiły się też XML i XSL, technologie, które występują
równieżjako części innych specyfikacji (XHTML, XSLT, Xpath, ICE itd.).
Poświęć trochę czasu na zrozumienie, jaki zestaw funkcji każda z nich zawiera i która
może przydać się przy tworzeniu twojej witryny. Podstawowe pytanie, które powinieneś sobie zadać przy tworzeniu konkretnego zadania, to: gdzie następuje przetwarzanie, na kliencie czy na serwerze.
44___________________________________________Część l
»
Podstawy PHP
Technologie wykonywane po stronie klienta Najwięcej rozszerzeń HTML wykorzystuje się po stronie klienta. Zawierają one: rozszerzenia formatowania, jak Cascading Style Sheet i Dynamie HTML, języki skryptów wykonywanych na kliencie i aplety Java. Obsługa tych technologii może być wbudowana w przeglądarkę (zadania wykonywane przez te technologie opisane są w tabeli 2.1). Tabela 2.1.
Rozszerzenia HTML po stronie klienta Technologia
Główne zastosowanie
Cascading Style Sheet, Dynamie HTML
Formatowanie stron: kontrolowanie rozmiaru, koloru, położenia, układu, czasu pojawienia się elementów
Skrypty wykonywane na kliencie
Obsługa zdarzeń: kontrola
(JavaScript, VBScript)
skutków definiowanych zdarzeń
Aplety Java
Dostarczanie małych oddzielnych aplikacji
Przykład efektów
Nakładanie, różne kolory i rozmiar, czcionki, warstwy
Połączenia, które zmieniają kolor
po najechaniu na nie myszą,
kalkulator kredytowy
Obracające się logo, krzyżówka, puzzle
Strona na rysunku 2.3 ma tę samą zawartość co strona na rysunku 2. l. Rysunek 2.3.
Przy Mad HTML
ze skryptami
wykonywanymi
po stronie klienta
Rozdział 2. » Skrypty wykonywane na serwerze WWW________________________45
Co oznacza „dynamiczny"
Często zaznacza się podział pomiędzy „statycznymi" i „dynamicznymi" stronami HTML — „dynamiczny" oznacza prawie wszystko, co wykracza ponad czysty HTML. Termin ten jest używany do opisu funkcji klienta i serwera. W przypadku klienta mogą to być prezentacje multimedialne, przewijające się nagłówki, automatycznie uaktualniające się strony lub elementy, które pojawiają się i znikają. Dla serwera termin ten oznacza, że zawartość stron jest tworzona na bieżąco.
Jak można zauważyć w źródłach, w przykładzie tym dodano arkusze stylów i skrypty
wykonywane na kliencie oraz nieco bardziej skomplikowany kod HTML.
A p p l e < / A > : Carlton, Jim ( 1 9 9 7 ) Insanely Great:
Levy, Steveri (1993)
Odyssey: Pepsi to
Apple: Sculley, John (1997) Steve Jobs and the NeXT Big Thing: Stress, Randall (1993)
Dell Computer
D i r e c t from Dell
: Dell, Michael (1999)
InteK/H5>
O n l y the Paranoid Survive:
Grove, Andrew S. (1996) I n s i d e I n t e l < / A > : Jacksvn, Tim ( 1 9 9 7 )
Sun Microsystems
H i g h N o o n < / A > : Southwick, Karen ( 1 9 9 9 )
Niestety, najlepszą cechą technologii działających po stronie klienta jest również najgorszą: są one całkowicie zależne od przeglądarki. Istnieją spore różnice w możliwościach przeglądarek, a nawet pomiędzy różnymi wersjami tej samej przeglądarki. Tak zwany Dynamie HTML to dwie różne koncepcje skryptów, którym zdarzyło się mieć tę samą nazwę. Można, niestety, skonfigurować przeglądarkę w sposób sprawiający kło-
poty: niektórzy wyłączają JavaScript ze względów bezpieczeństwa, co powoduje niemożność obejrzenia stron, które używają JavaScript do nawigacji (umyślnie zrobiliśmy to w przykładzie powyżej). Nie ulepsza się też przeglądarek z powodu kosztów lub kłopotów technicznych. Doświadczeni projektanci WWW powinni również pomyśleć o przeglądarkach tekstowych, dostępności i globalnym zasięgu. Nieprzypadkowo duże witryny, o masowej oglądalności, starają się trafić do możliwie dużej widowni. Chociaż Yahoo! i Amazon nie używają arkuszy stylów i JavaScript i to po ponad trzech latach od wprowadzenia tych standardów. Mimo nalegań World Wide Web Consortium wiele witryn uparcie trzyma się znaczników FONT i atrybutu BGCOLOR jako jedynego sposobu dotarcia do klientów używających AOL 3.0 w pięcioletnich komputerach Macintosh z 13-calowymi ekranami. Opór użyt-
kowników przed uaktualnieniem jest przekleństwem projektantów rozwiązań wykorzystujących technologie klienckie. Ironicznie można podsumować to w sposób następujący: po pięciu latach gwałtownego rozwoju Sieci jedyną rzeczą, której projektant może być pewien jest fakt, że klient na ekranie monitora zobaczy czysty tekstowy HTML (lub raczej podzbiór HTML, który jest powszechnie obsługiwany i przetrwał próbę czasu).
Rozdział 2. » Skrypty wykonywane na serwerze WWW_______________________47_
Aplety Java
Aplety Java, znane również pod nazwą „Java na stronie klienta", są uważane za mniej zależne od przeglądarki niż inne technologie klienckie. Jak sugeruje nazwa, są to małe aplikacje, które są przesyłane przez Internet. Jednak zamiast współdziałać bezpośrednio z systemem operacyjnym, jak aplikacje napisane w innych językach programowania, aplety Java działają na warstwie pośredniczącej, zwanej maszyną wirtualną Javy (JVM). Maszyna wirtualna może być rozumiana jako system operacyjny działający na prawdziwym systemie operacyjnym maszyny. Najnowsze przeglądarki posiadają maszynę wirtualną Javy, ale także można ściągnąć ją oddzielnie. Taki podział zadań pozwala apletom używać możliwości przeglądarki bez ograniczania przez jej relatywnie ubogi zakres funkcji. Aplety ucierpiały z powodu opinii o ich niewielkiej przydatności, ponieważ na początku były używane do tworzenia trywialnych „tańczących literek": logo, które wygląda jak zrobione z żelatyny, przewijane nagłówki, skaczące połączenia i inne przyprawiające o ból głowy błahostki.
Technologie klienckie nie potrafią zrobić niczego, co wymaga podłączenia do bazowego serwera. JavaScript nie może utworzyć indywidualnych list rozwijalnych na podsta-
wie danych użytkownika, zapisanych w bazie danych — gdy wymagana jest zmiana
w liście, programista musi zrobić to ręcznie (istnieje wersja JavaScript do wykonywania na serwerze, ale nie jest zbyt rozpowszechniona). Jest to nisza, którą mogą wypełnić skrypty wykonywane na serwerze.
Podsumowując: cokolwiek, co można zrobić z wyglądem lub zdarzeniami, dzieje się w komputerze klienta.
Skrypty wykonywane na serwerze Rysunek 2.4 zawiera schemat przepływu danych przy użyciu skryptów na serwerze. Skrypty wykonywane na komputerze klienta stanowią powabną, przyciągającą wzrok
część programowania dla WWW. W przeciwieństwie do nich skrypty dla serwera są niewidoczne dla użytkownika.
Skrypty dla serwera WWW są najczęściej wykorzystywane do połączenia witryn WWW z bazowymi serwerami, np. serwerami baz danych. Pozwala to na dwukierunkową komunikację: * Serwer do klienta: strony WWW mogą być tworzone z wyniku działania bazowego serwera. * Klient do serwera: strony są tworzone zgodnie z danymi wprowadzonymi przez użytkownika. Najczęstszym przykładem interakcji klienta z serwerem są formularze i listy rozwijalne, które są dynamicznie tworzone przez serwer.
48__________________________________________Część l
»
Podstawy PHP
Rysunek 2.4.
Zadania na serwerze
Skrypty dla serwera składają się z dwóch głównych elementów: języka skryptowego i maszyny skryptowej (która może, ale nie musi być wbudowana w serwer WWW). Maszyna skryptowa analizuje i interpretuje strony zapisane w znanym jej języku. Często obie części
są stworzone przez tę samą firmę lub zespół i mogą być używane tylko razem. Przykładem tego jest zarówno ColdFusion, jak i PHP 3. Istnieją jednak wyjątki od tej reguły. Java Server Pages są napisane w zwykłym języku programowania, a nie w specjalnym języku skryptowym. Stworzono kilka maszyn skryptowych wykorzystujących ten język, np. Allaire JRun, Apache JServ. Teoretycznie ASP pozwala na użycie dowolnego języka skryptów i kilku z maszyn skryptowych zgodnych z ActiveX (jednak w praktyce problematyczne jest użycie czegoś innego niż kombinacja NT, US, VBScript, JScript). PHP jest
również dwuczęściową technologią skryptową, ponieważ maszyna skryptowa (Zend) jest
oddzielona od języka programowania.
Rysunek 2.5 pokazuje prosty przykład skryptów dla serwera. Strona tworzona jest na bieżąco na podstawie bazy danych i źródła interpretowanego przez serwer, wynik jest przesyłany do klienta. W przykładzie poniżej załączyliśmy również odwołania do bazy danych (nie zajmowaliśmy się nimi do tej pory) i pozostawiliśmy dołączane pliki, ponieważ zadaniem tego przykładu jest przedstawienie wyniku działania PHP, a nie gotowego kodu. Tak wygląda źródło na serwerze:
Przykład: Przewodnik po książkach TechBiz. Dane z serwera
Rozdział 2.
»
Skrypty wykonywane na serwerze WWW_______________________49
Rysunek 2.5.
Przyktad skryptów dla serwera
Książki o
mysql_select_db("techbizbookguide") or die("Błąd otwarcia bazy danych");
S fquery = "SELECT Blurb FROM Company WHERE CompanyName = '$co'"; Sqresult = mysql_query($query) or die(mysql_error()); $blurb = mysql_fetch_array($qresult} or die(mysql_error(}); print("$blurb[0]"); ?>
bookinfo WHERE CompanyName='$co' ORDER BY AuthorLast";
$qresult2 = mysql_query{$query2} or die(mysql_error());
Książki o A p p l e < / H 2 X B R X / I D X / T R >
Założone w roku 1976 przez dwóch hobbystów, Steve Jobs i Steve W o z n i a k , w garażu. Pomogli rozkręcić przemysł komputerów osobistych przy pomocy ich stylowych, p r z y j a z n y c h komputerów. < / T D x / T R >
Apple
Jim Carleton
Insanely G r e a t < / A X / T D >
Steven Levy
0dyssey: Pepsi to AppleJohn Sculley Steve Jobs and the NeXT Big ThingRandall Stross
Rozdział 2. » Skrypty wykonywane na serwerze WWW_______________________51^
Przedstawiona strona nie imponuje w porównaniu ze stroną pokazaną na początku rozdziału, jeżeli patrzymy na źródło. Jednak nadając jednej zmiennej inną wartość spowodujemy, że dowolna liczba niezależnych stron będzie wyglądać inaczej. Weźmy za przykład stronę z książkami autorów o innym, niż podano, nazwisku. Jeżeli dodamy do bazy danych zapisy o książkach na temat innych firm, niż te które znajdują się w przykładach, lista zostanie automatycznie zaktualizowana. Jak można się zorientować z podanych przykładów, nie ma możliwości obejrzeć skryptów dla serwera z końcówki klienta. Tworzenie strony jest realizowane przed wysłaniem jej do klienta. Po wyjściu z serwera WWW strona wygląda jak zwykła strona HTML. Oznacza to, że nie możesz powiedzieć, jakiego użyto języka skryptowego, chyba że istnieje taka informacja w nagłówku. Skrypt pokazany w ostatnim przykładzie był napisany w PHP dla bazy danych MySQL. Współpraca pomiędzy tymi dwoma programami zostanie opisana w drugiej części tej książki.
Do czego są dobre skrypty serwera Klient dobrze wygląda, ale serwer świetnie pracuje. Skrypty dla serwera są atrakcyjne z powodu dużej użyteczności. Większość użytkowników WWW często korzysta z wyników działania skryptów serwera. Dwa bilety do raju
Wiele czynności można zrealizować używając skryptów dla klienta lub dla serwera. Na przykład wysyłanie poczty elektronicznej: używając skryptów klienta (gdy użytkownik kliknie łącze MAILTO) otwieramy program pocztowy zainstalowany na kliencie, uzupełniając odpowiednio pole adresu. Jeżeli chcemy użyć skryptów dla serwera, tworzymy formatkę, którą formatujemy jako e-mail i wysyłamy przez serwer SMTP. Można wybrać jedno z tych podejść, aby skontrolować poprawność formatki, tworzenie list rozwijalnych i obliczeń matematycznych. Czasami występują nieznaczne, jednak ważne różnice przy realizacji zadania (listy tworzone przez serwer mogą być tworzone dynamicznie). Jak wybrać właściwe rozwiązanie? Skrypty wykonywane na serwerze są zwykle nieco wolniejsze z powodu dodatkowych transmisji, jednak możliwości przeglądarki klienta ich nie ograniczają (dlatego zabiera konserwacja mniej czasu). To dobre rozwiązanie dla witryn o masowej oglądalności lub witryn edukacyjnych. Jeżeli jesteś pewien, że użytkownicy mają najnowsze przeglądarki i dużą przepustowość łącza, możesz śmiało stosować skrypty i grafikę. Pamiętaj, że PHP może generować zarówno statyczny HTML, jak i skrypty JavaScript. Metoda ta będzie opisana w dalszej części książki.
52__________________________________________Część
l
»
Podstawy
PHP
Istnieje jedna dziedzina zastosowań, w której serwer nie potrafi pomóc: trójwymiarowe
gry zręcznościowe. Im krótszy wymagany czas odpowiedzi, tym mniej użyteczny jest
do tego PHP. W chwili obecnej Sieć jest zbyt powolna na takie zastosowania (jednak pionierzy szerokiego pasma starają się to zmienić). Najbardziej użytecznymi zastosowaniami języków skryptowych, takich jak PHP, są: * witryny informacyjne (zarówno do tworzenia, jak i oglądania); * usługi dla grup (forum, tablica ogłoszeń itp.); ** e-mail (poczta dzięki WWW, przesyłanie); * systemy wsparcia technicznego i usług dla klientów; ** sieci reklamowe;
* aplikacje biznesowe dostępne dzięki WWW;
+ książki telefoniczne; * badania, ankiety, testy; ** wypełnianie i wysyłanie formularzy;
** personalizacja stron; * oprogramowanie korporacyjne; + katalogi, broszury, witryny informacyjne; * każda aplikacja, która łączy serwer usługowy (baza danych, LDAP, poczta itp.) z WWW. PHP zapewnia obsługę wszystkich tych zadań, a potrafi jeszcze więcej. Wystarczy tej retoryki! Masz teraz jasny opis różnic pomiędzy technologiami dla serwera i dla klienta, więc należy je zastosować w praktyce. Pokażemy teraz, jak zainstalować i skonfigurować PHP (możesz też znaleźć kogoś, kto zrobi to za ciebie...). Programowanie a pisanie skryptów Różnica pomiędzy programowaniem a pisaniem skryptów coraz bardziej się rozmywa. PHP używa większości podstawowych struktur stosowanych w innych językach programowania. Niektóre w pełni interpretowane języki wbudowywane w HTML, jak na przykład ASP, nadal są uważane za języki skryptowe, natomiast języki dostarczające osobnych plików binarnych — jako przykład klasycznego programowania. PHP 4 jest dynamicznie kompilowany (postać binarna jest przechowywana i używana aż do zmiany w kodzie) i jest oficjalnie „prawdziwym" językiem programowania. Zmiana ta, wraz z oszałamiającą prędkością działania, przesuwa PHP do tej samej klasy w której mieści się Perl.
Rozdział 2. » Skrypty wykonywane na serwerze WWW_______________________53^
Podsumowanie Aby wiedzieć, jakie zadania można wykonać za pomocą PHP (lub innego języka skryptowego serwera), musisz dokładnie poznać granicę pomiędzy pracą na serwerze
i na komputerze klienta. W rozdziale tym przedstawiliśmy przykłady zwykłego statycznego HTML, HTML z dodanymi rozszerzeniami CSS i kodem JavaScript, umożliwia-
jącym interakcję z klientem, a także wygenerowaną przez PHP stronę, przedstawioną zarówno z punktu widzenia serwera, jak i klienta. Skrypty wykonywane na kliencie pozwalają na atrakcyjną oprawę strony i działają szybko, ale wszystkie rozszerzenia, wykraczające poza podstawowy kod HTML, zależą od rodzaju przeglądarki. Jeżeli statyczne skrypty po stronie klienta nie są tworzone na podstawie stale zmieniającej się składnicy danych, ich utrzymanie i zmiana wymagają
czasu. Programowanie w językach skryptowych wykonywanych na serwerze, takich jak
PHP, pozwala na podłączenie serwerów baz danych i innych serwerów usługowych do stron WWW.
Architektura PHP 4 różni się znacznie od konstrukcji innych narzędzi do programowania na serwerze, a nawet od PHP 3. Jest on dynamicznie kompilowany, co znacznie przyspiesza jego pracę. W PHP 4 odseparowano maszynę skryptową Zend od języka
skryptowego.
j**_____________________.____________________
Część l » Podstawy PHP
Rozdział 3.
Rozpoczynamy pracę z PHP W tym rozdziale: * Decydujemy się na własny serwer lub dzierżawę * Szukanie właściwego dostawcy Internetu
* Częste problemy z dostawcami ** Instalowanie PHP * Wybór narzędzia programowania dla PHP W tym rozdziale przedyskutujemy wady i zalety różnych możliwości dostępu do serwera WWW: dzierżawę, własny serwer lub możliwości pośrednie. Następnie przedstawimy szczegółowe wytyczne instalowania PHP. Na koniec kilka porad w sprawie wyboru narzędzia programowania dla PHP. Po przeczytaniu tego rozdziału będziesz przygotowany do napisania pierwszego skryptu.
Dzierżawa lub własny serwer Pierwszą ważną decyzją, jaką musisz podjąć, jest wybór, gdzie będzie znajdować się twoja witryna wykorzystująca WWW: w twoim komputerze, czy u dostawcy Internetu. Jeżeli tę decyzję masz już za sobą, możesz przejść od razu do części o instalowaniu PHP.
Wariant z dostawcą Internetu Uruchamianie witryn w komputerach dostawców Internetu staje się coraz bardziej popularne wśród firm udostępniających witryny WWW. Poniżej przedstawimy wady i zalety takiego wyjścia.
Hakerzy, brak prądu czy pogięte taśmy backupu nie są już twoim zmartwieniem. To pracownik dostawcy usług internetowych dostaje informację, że coś złego dzieje się z t woj ą witryną, i musi się zająć kłopotem. Dzierżawa serwera jest w wielu przypadkach bardzo korzystna finansowo. PHP na Linuksie lub którymś BSD jest tani i dostępny. W chwili obecnej niewielu dostawców oferuje PHP na platformie NT (zwykle drożej).
Wady Ale dzierżawa serwera ma też swoje wady... Większość jest związana z kontrolą. Jeżeli korzystasz z usług dostawcy, jesteś gościem i musisz dostosować się do jego zasad (mimo, że płacisz i wymagasz). Głównym problemem związanym z PHP jest sposób jego pracy — moduł serwera lub CGI. PHP działa lepiej jako moduł, jest wtedy wbudowany w serwer, a nie jest osob-
nym procesem. Prawie wszyscy wolą uruchamiać PHP jako moduł, jednak dostawcy
niekiedy uruchamiają go jako CGI, ponieważ wtedy łatwiej nim bezpiecznie administrować. Są oczywiście dostawcy oferujący PHP działający jako moduł serwera, ale są
to zwykle mniejsze firmy oferujące niższą przepustowość łącza. Istnieje jeszcze kilka
innych sytuacji, w których oczekiwania użytkowników pozostają w konflikcie z wygodą dzierżawy serwera.
Zwykle sprawdza się zasada: im mniej wyszukane żądania, tym bardziej możliwe i odpowiednie jest wydzierżawienie serwera. Najgorsze jest jednak to, że na ten sam serwer wpycha się coraz więcej witryn, czy tego chcesz, czy nie. Istnieje kilka czynników, które mogą spowodować duże kłopoty w znalezieniu odpowiedniego dostawcy.
Rozdział 3. » Rozpoczynamy pracę z PHP______________________________57
** Treści ogólnie uznane za niepożądane (przemoc, pornografia). ** Masowa poczta, znana jako spam. * Treści atrakcyjne dla hakerów (informacje o zabezpieczeniach). * Zawartość potencjalnie nielegalna. * Wymagany niestandardowy sprzęt, system operacyjny lub oprogramowanie.
+ Wymagana duża przepustowość. Jeżeli twoje wymagania należą do którejś z tych kategorii, musisz łapać każdą okazję, jaka się nadarzy. Pewnie nie będziesz miał dużego wyboru, jeżeli jednak znajdziesz dostawcę, który zgodzi się na utrzymywanie twojej witryny, podpisz umowę, zanim zmieni zdanie. Później będziesz mógł spokojnie szukać lepszego rozwiązania. Musimy również wspomnieć o najważniejszym negatywnym czynniku, występującym w przypadku usług niektórych dostawców: złości, spowodowanej awariami serwera właśnie w momencie, gdy twoja witryna zaczęła pojawiać się w rankingach popularności. To nawet gorsze od utraty poczty, znikania DNS-a, wiszenia godzinami przy telefonie w oczekiwaniu na kogoś z serwisu, braku odpowiedzi na uprzejme e-maile oraz notorycznego zawyżania rachunków. Jeżeli decydujesz się na dzierżawę, to na własną odpowiedzialność. Rozmawiając z dostawcą nie udawaj ignoranta, poświęć trochę czasu w poznanie podstawowych pojęć. Powinieneś w szczególności nauczyć się rozróżniać problemy, które są związane z konkretnym serwerem (nieprawidłowa konfiguracja), a tymi, na które nie mamy wpływu.
Szczegóły Gdy wybierzesz już sposób, w jaki będziesz chciał udostępnić witrynę, możesz wybrać spośród wielu ofert obecnych na rynku. Początkujący klienci powinni uważać. Słowo ISP może dziś znaczyć prawie wszystko. W tabeli 3.1 zestawiliśmy specjalizację różnych dostawców oraz ich potencjalnych klientów (firmy wymienione w tabeli są tylko przykładami, nie popieramy tych firm, ani nie rekomendujemy ich usług). Mimo, że znalezienie dobrego dostawcy Internetu czasami wydaje się tak samo trudne, jak znalezienie partnera na całe życie, istniej ą witryny WWW ułatwiające to zadanie: http://hosts.php. net
http://www. od-site. com/php http://www. ispcheck. com Zwróć uwagę na komentarze użytkowników, zarówno na te pozytywne, jak i negatyw-
ne. Spytaj przyjaciół i kolegów o opinie. Przeszukaj archiwa list dyskusyjnych — czasami zdarzają się rekomendacje oraz opisy niedobrych doświadczeń. Najważniejszym chyba zagadnieniem jest przepustowość łącza. Bądź ostrożny przy zdaniu „nielimitowany ruch, pasmo, liczba odwiedzin". Przypomnij sobie pytanie mądrego trenera w średnim wieku, gdy stary właściciel drużyny proponował mu pracę do
Wdzwanianie, ISDN, linie DSL, ADSL, modemy kablowe
Małe witryny (wizytówki)
Bezpłatna dzierżawa witryn (Linuxbox.com)
Bezpłatne pod pewnymi warunkami
Witryny nie nastawione na zysk lub witryny bezpłatnego oprogramowania
Dostawcy komercyjni
Serwery wirtualne, kolokacja, serwery dedykowane
Większość witryn
Tworzenie witryn
Projektowanie, promocja,
Dostawcy łącza
Witryny, które chcą również
konsulting
wynajmować projektantów
T-l, DS.-3, DSL, Frame Relay
Własne serwery
końca życia: „O jakim życiu myślisz?" Analogicznie, pasmo, jakiego nigdy nie zajmie witryna miłośników poezji epickiej Joego, nie będzie już wystarczające dla witryny oferującej bezpłatne transmisje video. Przed zawarciem kontraktu sprawdź, czy nie wpadniesz w pułapkę. W jaki sposób przewidzieć wymagane pasmo? l GB ruchu miesięcznie to 100 000 obejrzeń pliku o wielkości około 10 k (włączając w to grafikę, tekst i ogłoszenia, chyba że są ściągane z innego źródła, mierzone z klienta, a nie z serwera).
Bądź szczególnie ostrożny przy szacowaniu ilości miejsca potrzebnego dla witryny, szczególnie jeżeli zawiera ona dużo grafiki. Jeżeli przekroczysz limit miejsca, będziesz płacił wygórowane kwoty za każdy ułamek dodatkowego megabajta. Zwykle odpowiedzialne za to są pliki logów. Kasuj je lub ściągaj regularnie i przechowuj na nieco tańszym nośniku.
Własny serwer: wady i zalety Posiadanie własnego serwera jest realne, ponieważ ceny połączeń spadają. Jest to niezrównane rozwiązanie, jeżeli chodzi o konfigurację i kontrolę; zapewnia duże bezpieczeństwo — jeżeli potrafisz nim właściwie zarządzać. Uruchomienie własnej konfiguracji ułatwia rozwiązywanie problemów, ponieważ nie tracisz czasu na niekończące się rozmowy telefoniczne z serwisem dostawcy. Jeżeli masz niecodzienne lub budzące sprzeciw potrzeby, być może własny serwer będzie najlepszym rozwiązaniem. Jednak prowadzenie serwera wymaga o wiele więcej pracy i może być nieco droższe, szczególnie w przypadku małych i średnich witryn. Samodzielnie udostępniana witryna świadczy o twoich umiejętnościach. Jeżeli nikt z twojego otoczenia nie zna się dobrze na zagadnieniach bezpieczeństwa, możesz się spodziewać problemów.
Rozdział 3. » Rozpoczynamy pracę z PHP______________________________59
Mówiąc bardziej ogólnie, nie będziesz miał kogo winić, jeżeli coś pójdzie źle. Jeżeli możesz codziennie spojrzeć w lustro i powiedzieć: „To wszystko moja zasługa i dobrze mi z tym", masz dość pewności siebie, aby prowadzić własny serwer.
Rozwiązania pośrednie Pomiędzy własnym serwerem a wynajmowaniem witryny rozciąga się spektrum możliwości. Istnieje kilka kompromisowych rozwiązań czerpiących najlepsze cechy obu powyższych.
Kolokacja Kolokacja polega na zakupieniu własnego komputera i wstawieniu go do pomieszczenia dostawcy, gdzie zostanie wpięty do sieci i monitorowany. Jesteś odpowiedzialny za zakup sprzętu, licencji, zabezpieczenie, instalowanie, konfigurację oraz utrzymywanie oprogramowania i sprzętu, oprócz UPS-a. Jeżeli serwer będzie wymagał konfiguracji, będziesz musiał skonfigurować go sam lub zapłacić grube pieniądze za godzinę pracy
serwisanta. Jeżeli zdecydujesz się na kolokację, przygotuj się na to, że serwisant nie będzie miał żadnego doświadczenia z produktami, które zainstalowałeś na serwerze.
Serwer dedykowany Dedykowany serwer jest dokładnie tym, co wskazuje nazwa. Dostawca kupuje maszynę, konfiguruje ją według twojego życzenia (za twoje pieniądze oczywiście), włączają do sieci i od tej pory każdy cykl procesora należy do ciebie. Dostawca zapewnia zwykle wsparcie techniczne. Jest to bezpieczniejsze od dzierżawy i korzystne finansowo dla średnich i dużych witryn.
Dzierżawa serwera i własne środowisko programistyczne Opcja ta wymaga dwóch instalacji: witryny roboczej oraz identycznej instalacji na serwe-
rze przeznaczonym do jej tworzenia. Taki podział pozwala na korzystanie z najlepszych cech obu rozwiązań: kto inny ma pager powiadamiający w środku nocy o awariach, a ty masz własny serwer. Jeżeli mieszkasz na terenie, gdzie trudno o połączenie internetowe, rozwiązanie takie jest jedyne z możliwych. Jest też często stosowane w dużych witrynach, przy których pracuje wielu programistów.
Instalowanie PHP Jeżeli decydujesz się wydzierżawić kompletne środowisko programowania, możesz bez obawy opuścić resztę tego rozdziału (dotyczy tylko własnego serwera).
60__________________________________________Część
l
»
Podstawy
PHP
Zanim zaczniesz Przed rozpoczęciem instalacji PHP na jakiejkolwiek platformie będziesz potrzebował: * komputera z wystarczającą ilością pamięci dla systemu operacyjnego; * zainstalowanego systemu Unix lub Windows 95/98/NT/2000; * działającego połączenia z Internetem, jeżeli jest to witryna robocza lub instala-
cja w Intranecie do tworzenia witryny. Nie potrzebujesz połączenia, jeżeli jest
to całkowicie oddzielna instalacja.
Pomoc na wstępnym etapie wykracza poza ramy tej książki. Możesz zajrzeć do następujących witryn, aby zasięgnąć informacji: http://164.109.153.102/idgsearchresult.asp?searchtype=2?keyword=networking http://www. linuxdoc. org/HO WTO/HOWTO-INDEX/howtos. html
Jeżeli zamierzasz zainstalować PHP pod Windows, potrzebujesz: * działającego serwera WWW obsługującego PHP. Za czasów PHP 3 IIS/PWS były najlepszym rozwiązaniem, ponieważ istniał do nich moduł PHP. PHP 4 zapewnia szerszą gamę modułów dla Windows;
* zainstalowanej bazy danych obsługiwanej przez PHP (jeżeli chcesz używać bazy danych); * ścieżki do katalogu Windows (zwykle c:\windows dla Windows 95/98, będziesz musiał podać ten katalog przy instalacji na NT lub Windows 2000); * uaktualnienia DCOM dla Windows 95, dostępnego bezpłatnie pod adresem: http://do\vnload/microsoft.com/msdownloads/dcom/95/x86/en/dcom95.exe;
+ dystrybucji PHP dla Windows (www.php.net/downloads.php); + narzędzie do rozpakowywania plików .zip (poszukaj narzędzi kompresji pod
adresem http://download, cnet. com)
Jeżeli chcesz zainstalować PHP na Uniksie, potrzebujesz: * dystrybucję PHP (www.php.net/downloads.php); * ostatniej wersji serwera Apache (www.apache.org/dist/— szukaj pliku o najwyższym numerze, który kończy się na tar.gz); * zainstalowanej bazy danych obsługiwanej przez PHP (jeżeli chcesz używać bazy danych);
** innego oprogramowania, do którego ma się podłączyć PHP (serwera poczty, pakietu matematycznego, JDK itp.); + kompilatora ANSI C; * Gnu make (od PHP 4 może być to dowolna wersja make — możesz je bezpłatnie skopiować z www.gnu.org/software/make);
Rozdział 3. » Rozpoczynamy pracę z PHP______________________________61
* bison i flex (wpisz „find . -name bison -print" oraz „find . -name
flex -print" z katalogu /usr, aby sprawdzić, czy masz zainstalowane te
programy, lub pozwól gcc, aby sprawdził w trakcie instalacji, czy są dostępne. Jeżeli nie masz tych programów, możesz skopiować bison z www.gnu.org/software/bison, a flex z ftp://ftp.ee. lbl.gov);
* ścieżki do pliku konfiguracyjnego HTTP. Do niedawna były to access, conf, httpd.conf\ srm.conf dla serwera Apache, ale w tej chwili są połączone w jeden plik httpd.conf. Zależy to od systemu operacyjnego, dystrybucji, serwera WWW. Możesz użyć narzędzia Fin d, aby je odszukać;
* ścieżki do plików źródłowych Apache (zwykle /usr/local/apache_1.3.x);
* ścieżki do demona Apache znanego jako httpd (zwykle /usr/local/bin). Teraz jesteś gotowy do instalacji. Pamiętaj, że programy, z którymi PHP będzie się łączył, muszą być zainstalowane przed jego kompilowaniem. Baza danych jest najbardziej znanym typem serwera zewnętrznego. Innym przykładem jest biblioteka BCmath, serwer IMAP, biblioteka mcrypt czy analizator XML Expat.
Różnica pomiędzy kompilacją dla Apache a kompilacją jako CGI jest bardzo niewielka. Właściwie polega na ustawieniu opcji -with-apache lub -with-apxs w trakcie konfiguracji. Wielu użytkowników dla wygody kompiluje jednocześnie wersję dla Apache i CGI.
Procedura instalacji Z powodu niezależności PHP można zastosować wiele specyficznych metod instalacji, zbyt wiele, aby je tu wszystkie wymienić. Spróbujemy opisać tylko te, które uważamy za najbardziej popularne.
Windows NT/2000 i IIS Instalacja PHP pod Windows NT/2000 z serwerem IIS jest bardzo prosta. Należy pamiętać, że zasad stosowanych dla NT/2000 nie stosuje się dla Windows 95/98, i odwrotnie. W dalszej części rozdziału zamieściliśmy uwagi o instalacji pod 95/98, ta część jest poświęcona Windows NT/2000.
1. Rozpakuj archiwum używając narzędzia typu unzip. Umieść pliki w katalogu C:\PHP.
2. Skopiuj p\\kphp.ini-dist do katalogu Windows i zmień jego nazwę naphp.ini. 3. Przejdź do katalogu System32, który znajduje się w katalogu Windows. Powinieneś mieć wiele plików DLL. Poszukaj pliku msvcrt.dll, jeżeli go nie ma, skopiuj go z katalogu PHP. Skopiuj również p\ikphp4ts.dll do katalogu System32.
j62_______________________________________Część l » Podstawy PHP
4. Uruchom Microsoft Management Console (inaczej Internet Service Manager). Powinieneś zobaczyć graficzną reprezentację twojej witryny WWW (małe globusy).
5. Kliknij prawym przyciskiem myszy ikonę reprezentującą witrynę, w której chcesz uaktywnić PHP (utwórz nową, jeżeli jest to konieczne) i wybierz Prop-
erties. Kliknij zakładkę ISAP1filters. Kliknij Add, by dodać nowy filtr. Nazwij filtr PHP, a w polu Location wpisz c: \PHP\php4isapi. dli. Musisz wykonać tę czynność dla każdej witryny WWW osobno.
6. Kliknij zakładkę Home directory. Upewnij się, że zaznaczona jest opcja Execute permissions. Kliknij Configuration. Kliknij Add na zakładce Application mappings. Wpisz c: \ P H P \ p h p 4 i s a p i . dli w polu Executable, w polu Extension — .php, zaznacz Script Engine, a pole Method exclusions pozostaw puste. 7. Zatrzymaj i ponownie uruchom usługę WWW. Z menu Start wybierz Settings, Control Panel, Services. Przewiń listę, aż zobaczysz US Admin Service. Zaznacz tę usługę i kliknij Stop. Po zatrzymaniu usługi (pokaże się stosowny komunikat) zaznacz World Wide Web Publishing Service i kliknij Start. Zatrzymanie i uruchomienie za pomocą narzędzia Internet Service Manager (kliknięciem prawym przyciskiem myszy ikony globusa) może nie wystarczyć. Na koniec trzeba będzie ponownie uruchomić komputer. 8. Uruchom Notepad. Wpisz . Zapisz plik w głównym katalogu z dokumentami serwera WWW jako info.php. Uruchom przeglądarkę
i wczytaj utworzony plik. Musisz wczytać, go podając URL (www.testdomain.com/info.php] lub wywołanie HTTP (http://hostname/info.php), a nie nazwę pliku (c:\inetpub\wwwroot\info.php). Powinieneś zobaczyć długą tabelę z informacjami o nowej instalacji PHP 4. Gratulacje. Niektórzy użytkownicy Windows zgłaszali, że muszą umieścić plik php.ini w tym samym katalogu co php.exe. Nie jest to idealne rozwiązanie ze względów bezpieczeństwa, ponieważ lepiej usunąć ten plik z drzewa katalogów WWW. Jednak dopóki nie będziesz miał dostępu do źródeł tego systemu operacyjnego, nie wyeliminujesz problemu.
Unix i Apache Za pierwszym razem gdy będziesz tworzył demona HTTP ze źródeł, możesz mieć pewne obawy. Proces ten jest jasny; warto podjąć wysiłek kompilacji serwera WWW, zamiast zależeć od pliku RPM stworzonego przez kogoś innego. Poza tym własny serwer jest zwykle szybszy. Tych, którzy już kompilowali wcześniejsze wersje PHP, informujemy, że procedura jest identyczna, ale trwa dłużej. Fragmenty kodu, przedstawione w przepisie poniżej, trzeba wpisać w wierszu poleceń.
Rozdział 3. » Rozpoczynamy pracę z PHP________________________________63^
Instalacje Red Hat lub Mandrake Linux mogą być dostarczane z Apa-
che i PHP w postaci plików RPM. Musisz usunąć je przed rozpoczęciem kompilacji własnego PHP! Możesz dodatkowo mieć wersje RPM
innych serwerów, takich jak MySQL lub PostgreSQL, które instaluje się inaczej, niż ich odpowiedniki w postaci źródeł. Jeżeli napotkasz problemy, wyrzuć pliki RPM i zainstaluj program ze źródeł.
Załoguj się jako użytkownik root.
1. Rozpakuj programem unzip i tar dystrybucję Apache, jeśli jeszcze tego nie zrobiłeś. Umieść je w /usr/local, jeżeli nie ma do tego przeciwwskazań. gunzip -c apache_l.3.x.tar.gz tar -xf apache_l.3.X.tar
cd apache_1.3.x ./configure
2. W analogiczny sposób rozpakuj i umieść dystrybucję PHP. Jeżeli Apache i PHP nie znajdują się w tym samym katalogu, musisz poniżej zamieniać każdy ciąg „.." na pełną ścieżkę do odpowiedniego pakietu. cd . . gunzip -c php-4.x.tar.gz tar -xvf php-4.x.tar cd php-4.x
3. Teraz należy skonfigurować tworzony pakiet (konfiguracja PHP jest obszernym i skomplikowanym zagadnieniem, które nie zmieści się w tym rozdziale, więc osoby zainteresowane powinny przejść rozdziału 31.). Najczęściej używana jest opcja tworzenia modułu Apache oraz obsługa wybranej bazy danych. Obsługa języka Java oraz XML staje się coraz popularniejsza. Poniższy przykład kompiluje PHP jako moduł Apache z obsługą MySQL i XML. Twoje opcje mogą być inne. . / c o n f i g u r e - - w i t h - a p a c h e - . . / a p a c h e _ l . 3 . x --with-mysql -with-xml ^--enable-track-vars
4. Utwórz i zainstaluj moduł PHP make
make install
5. Skonfiguruj i skompiluj demona Apache. W poniższym przykładzie /etc/httpd jest ścieżką do pliku konfiguracyjnego (np.: /conf/httpd.conf); jeżeli twój plik znajduje się gdzieś indziej, wpisz odpowiednią ścieżkę. Jeżeli używasz najnowszej wersji Apache z plikami konfiguracyjnymi w apache_1.3.x/confi nie masz wcześniejszych plików konfiguracyjnych, możesz z poniższego przykładu usunąć -prefix. cd . . /apache_l.3.x . / c o n f i g u r e - - p r e f i x = / e t c / h t t p d --activate-module 3>=src/modules/php4 / I i b p h p 4 . amake
t
6. Zatrzymaj i zamień plik wykonywalny httpd. Istnieje kilka sposobów na za-
trzymanie i uruchomienie httpd. Jeżeli stosujesz inną metodę, nie ma powo-
64__________________________________________Część
l
»
Podstawy
PHP
dów, abyś jej nie używał. Jeżeli jest to konieczne, zamień /usr/local/bin na właściwą ścieżkę do twojego demona HTTP. Jeżeli jesteś pewien, że nie masz httpd, możesz po prostu wykonać make install. W środowiskach, w których wymagana jest wysoka dostępność, możesz wstrzymać wykonanie tego etapu aż do zakończenia konfigurowania PHP i Apache (punkty 7. i 8.), co spowoduje chwilowe przerwanie funkcjonowania witryny WWW. cd src/support
./apachectl stop cd . . cp httpd /usrlocal/bin
7. Ustaw zawartość p\ikuphp.ini. Lista opcji zamieszczona jest w rozdziale 31. Nowym użytkownikom polecamy ustawienie raportowania błędów na E_ALL. cd ../../php-4.x
cp php.ini.dist /usr/local/lib/php.ini
8. Poinformuj serwer WWW, jakiego rozszerzenia chcesz używać do identyfikacji plików PHP (.php jest standardem, ale możesz użyć .html, .phtml lub innego). Przejdź do plików konfiguracyjnych HTTP (/etc/httpd/conf lub inna ścieżka, jaką masz w systemie) i otwórz plik httpd.conf(\ub srm.confwe wcześniejszej wersji plików konfiguracyjnych Apache) za pomocą edytora. Dodaj co najmniej jeden wiersz z definicją rozszerzenia dla PHP, tak jak pokazuje to pierwszy wiersz przykładu. W drugim dodajemy definicję nakazującą analizę wszystkich plików HTML. AddType application/x-httpd-php .php
AddType application/x-httpd-php .html
9. Uruchom serwer. Za każdym razem gdy zmienisz konfigurację lub zawartość pliku php. ini, będziesz musiał zatrzymać i uruchomić ponownie serwer. Wysłanie sygnału HUP nie wystarczy. cd ../apache_l.3.x/src/support ./apachectl start
10. Nadaj uprawnienia dostępu do katalogu głównego z dokumentami wszystkim użytkownikom. Wystarczy, że użytkownicy będą mieli prawo czytania plików PHP. Jeżeli jest to konieczne, zamień /home/httpd/html/php na ścieżkę do twojego katalogu z dokumentami. chmod 755 /home/httpd/html/php
11. Uruchom edytor tekstu. Wpisz . Zapisz plik w głównym katalogu z dokumentami serwera WWW jako info.php. Uruchom przeglądarkę i wczytaj utworzony plik. Musisz wczytać go, podając URL (www.testdomain. com/info.php) lub wywołanie HTTP (http://localhost/info.php), a nie nazwę pliku (/home/httpd/html/info.php). Powinieneś zobaczyć długą tabelę z informacjami o nowej instalacji PHP 4. Gratulacje.
Windows 95/98 i PWS Częstą, aczkolwiek niezbyt szczęśliwą sytuacją jest sprawdzanie działania PHP jak najmniejszym kosztem (szczególnie dotyczy nowych użytkowników Windows) i instalacja PHP pod Windows 95/98 z serwerem WWW Personal Web Server. Nie jest to najlepszy pomysł!
Rozdział 3. » Rozpoczynamy pracę z PHP________________________________65
Windows 95/98 nie był projektowany jako platforma dla serwerów. Aby zainstalować serwer WWW i maszynę skryptową, należy dosyć głęboko „wkopać się" w rejestr. Jeżeli coś pójdzie źle, system nie zadziała. Jeżeli zaś zdecydujesz się usunąć PHP z komputera, nie będzie to prosta operacja usunięcia plików — należy przywrócić pierwotną postać zapisów w rejestrze. Istnieje skrypt instalujący PHP, ale nie ma skryptu usuwającego go z systemu. Jeżeli decydujesz się na tę instalację mimo naszych ostrzeżeń, postępuj zgodnie z następującymi wskazówkami.
1. Jeżeli pracujesz z Windows 95, zainstaluj poprawkę DCOM.
2. Rozpakuj archiwum zip i umieść jego zawartość w katalogu C:\PHP. 3. Skopiuj plik php.ini-dist z katalogu PHP do katalogu Windows i zmień jego nazwę na php. ini. Plik musi być skopiowany przed wykonaniem następnych czynności, inaczej instalacja się nie uda.
4. Przejdź do katalogu System, który znajduje się w katalogu Windows. Zobaczysz sporo plików DLL. Sprawdź, czy znajduje się tutaj plik msvcrt.dll; jeżeli go nie ma, skopiuj go z katalogu PHP. Skopiuj również do katalogu System p\ikphp4ts.dll. 5. Otwórz plik php.ini. Zmień ustawienie extension_dir na c:\php (tak, jak
nazwałeś katalog z PHP). Ustaw zmienną doc_root, aby wskazywała na główny katalog dokumentów serwera WWW (c:\webroot). Usuń komentarze przy właściwych wierszach extension=php_* .dli, aby załadować dodatkowe moduły.
6. Wskaż PWS, gdzie znajdzie moduł ISAPI. Aby to zrobić, dodaj ścieżkę ISAPI do pliku PWS-php4.reg, który znajdziesz w plikach dostarczanych z instalacją
PHP (czytaj podwójny backslash jak pojedynczy). Jeżeli zainstalowałeś PHP
w innym katalogu niż c:\php, musisz zmienić ścieżkę w pliku .reg ".php"=C:\\PHP\\php4isapi.dli"
7. Otwórz PWS Manager. Kliknij prawym przyciskiem myszy katalog z dokumentami (na przykład c:\webroof) i wybierz Properties. Zaznacz Execute i potwierdź. Uruchom ponownie komputer.
8. Uruchom Notepad. Wpisz . Zapisz plik w głównym katalogu z dokumentami serwera WWW jako info.php. Uruchom przeglądarkę i wczytaj utworzony plik. Musisz wczytać go, podając URL (www.testdomain. com/info.php) lub wywołanie HTTP (http://hostname/info.php), a nie nazwę pliku (c:\inetpub\wwwroot\info.php). Powinieneś zobaczyć długą tabelę z informacjami o nowej instalacji PHP4. Gratulacje.
Nawet jeżeli jest możliwe użycie nazw katalogów zawierających spacje, nie zalecamy używania ich pod Windows dla katalogów zawierających pliki PHP. Zwykle powodują problemy.
Inne serwery WWW PHP działa doskonale również z innymi serwerami WWW, takimi jak Netscape Enterprise Server, Xitami, Zeus i thttpd. Zespół programistów zapowiedział wersję pracującą jako moduł NSAPI (i prawdopodobnie również innych serwerów). Niestety w czasie
wydawania książki procedura takiej instalacji nie była udokumentowana lub była udokumentowana słabo. Jeżeli potrzebujesz informacji o różnych instalacjach PHP, sprawdź
pod następującymi adresami.
Apache dla Windows (wersja CGI): http://www. apache, org/docs/windows. html fhttpd:
http://ww\v.fhttpd. org/www/install.html Omni:
http ://www. umcsd. k!2. or. us/php/win32install. html
Narzędzia programistyczne PHP nie posiada luksusowego graficznego środowiska programistycznego, z kreatorami, polami wyboru czy ikonami. Jeżeli takie rzeczy są dla ciebie istotne, możesz używać edytora typu WYSIWIG do formatowania stron, a następnie ręcznie dodawać funkcje PHP. Wadą takiej strategii może być nieczytelność kodu napisanego przez program. Szczególnie uważaj na Microsoft FrontPage, który sprawia użytkownikom chyba najwięcej problemów. Musisz używać znaczników w standardzie ASP (wybór opcji w pliku php.ini) lub stosować znaczniki w standardzie JavaScript, co może być uciążliwe.
Wydaje się, że większość użytkowników PHP woli używać edytorów tekstowych. Programy te powinny zapewniać minimum pomocy, na przykład podświetlanie składni, odszukiwanie nawiasów, domykanie znaczników. Większość z tych opcji pozwala na zmniejszenie liczby pomyłek i działa jako podręczna ściągawka, nie tworząc pliku za ciebie. Pamiętaj, że program ten nie musi znajdować się na tej samej maszynie co serwer. Jest
to szczególnie przydatne, jeżeli używamy Uniksa, w którym (parafrazując Blues Brothers) „mamy oba rodzaje edytorów: emacs i vi". Macintosh, BE i Windows posiadają szeroką gamę sprytnych i przyjaznych edytorów tekstu. Patrząc z drugiej strony, Unix ułatwia obsługę wielu systemów klienckich. Wielu programistów korzysta z zalet obu rozwiązań.
Keith Edmunds prowadzi długą listę edytorów obsługujących PHP, wiele z nich można uzyskać bezpłatnie albo za niewielką kwotę: http:'//www. itworks. demon. co. uk/phpeditors. htm
Rozdział 3. « Rozpoczynamy pracę z PHP________________________________67^ Tabela 3.2.
Znane edytory PHP dla różnych platform Platforma
Produkt
Opis
Macintosh
BBEdit (www.barebones.com)
Pakiet WYSIWYG Macromedia Dreamweaver dla Maca
Unix
emacs (www.emacs.org)
i xemacs (www.xemacs.org)
Podświetlanie składni dla xemacs (może działać w emacs) jest
dostępne pod adresem http://www.cs.huji.ac.il/~baryudin
/php3 _mode.html. vim (www.vim.org). Ulepszona wersja vi. Czołowy edytor hakerów Uniksa, z podświetlaniem składni PHP. Dostępny dla prawie wszystkich systemów operacyjnych
Windows
HomeSite (www.allaire.com/homesite)
Ciągle popularny komercyjny edytor dla Windows. Zawiera Macromedia Dreamweaver. Notepad, dołączony do każdej
wersji Windows. Możesz wierzyć lub nie, ale wielu ludzi tworzy świetne witryny przy użyciu prostych narzędzi
Słyszeliśmy plotki, że Zend pracuje nad bogatym środowiskiem IDE dla PHP. Jednak w czasie wydawania książki nie zostały one potwierdzone.
Weź głęboki oddech. Po zainstalowaniu i skonfigurowaniu PHP będziesz gotów do napisania pierwszych skryptów.
Podsumowanie Zanim będziesz mógł używać PHP, musisz zdecydować, czy będziesz utrzymywał serwer WWW, czy go wydzierżawisz, czy wreszcie wybierzesz jakieś kompromisowe rozwiązanie, np. kolokację. Wybór determinują: koszt, rozmiar i wielkość ruchu generowanego przez witrynę, nietypowe wymagania sprzętowe lub programowe oraz rodzaj prezentowanych stron. Najlepszym wyjściem dla małej witryny bez specjalnych wymagań jest dzierżawienie serwera.
Jeżeli zdecydowałeś się na uruchomienie własnego serwera, masz już informacje o najczęściej używanych platformach. PHP 4 obsługuje wiele serwerów WWW, ale opis wszystkich instalacji nie był dostępny. Na koniec zastanawialiśmy się, jakie narzędzia programistyczne najlepiej nadają się do PHP. W chwili obecnej nie ma jeszcze zintegrowanego środowiska dla PHP, a większość programistów używa po prostu ulubionego edytora tekstu. Można również dodawać PHP do stron zbudowanych przez graficzny edytor HTML, ale trzeba przygotować
się na kłopoty.
68
Podstawy PHP
Rozdział 4.
Dodajemy PHP do HTML W tym rozdziale:
* Przełączanie się do trybu PHP 4 Wybór stylu znaczników PHP * Piszemy w PHP program „Witaj świecie" ** Pliki dołączane i wymagane
Po tych czynnościach wstępnych możemy się wreszcie zabrać za napisanie pierwszego
skryptu PHP. W rozdziale tym opiszemy tryb PHP, znaczniki oraz sposób dołączania
innych plików i pliki wymagane. Napiszesz również pierwszy skrypt PHP.
HTML jest gotowy na PHP PHP jest świetnie zadomowiony w HTML (musi tak być, ponieważ jest w niego wbudowywany). Później zobaczysz, w jaki sposób PHP wykorzystuje sprytniejsze części
standardu HTML, takie jak formularze, do robienia różnych pożytecznych projektów.
Wszystko, co jest prawidłowym kodem HTML u klienta jest zgodne z PHP. PHP nie przejmuje się fragmentami w JavaScript, wywołaniami dźwięków i animacji, apletów i innych elementów działających u klienta. PHP ignoruje te fragmenty, a serwer po pro-
stu przesyła całość do klienta.
Powinno być już jasne, że możesz użyć dowolnej metody tworzenia strony WWW i dodawania do niej kodu PHP. Jeżeli pracujesz nad stronami w grupie, używając dużych multimedialnych pakietów, możesz nadal tak pracować. Nie potrzebujesz radykalnej zmiany narzędzi czy przebiegu pracy — rób to, co do tej pory, a na koniec dodaj do kodu skrypty serwera.
70__________________________________________Część
l
»
Podstawy
PHP
Przełączanie się z HTML do PHP W jaki sposób wskazujemy sekcję PHP w kodzie HTML? Używa się do tego celu znaczników PHP na początku i końcu każdej sekcji. Proces ten nazywamy przełączaniem z kodu HTML do PHP. Wszystko pomiędzy tymi znacznikami jest traktowane przez moduł lub CGI jako PHP. Tekst na zewnątrz sekcji PHP nie interesuje serwera i po prostu jest przesyłany do klienta bez względu na to, czy jest to HTML, JavaScript lub cokolwiek innego.
Można stosować cztery rodzaje znaczników PHP, według własnego uznania i wygody, w różny sposób uzasadniając ich użycie.
Kanoniczne znaczniki PHP Najbardziej uniwersalnym stylem znaczników PHP jest
?>
Jeżeli używasz takich znaczników, możesz być pewien, że znaczniki te będą zawsze poprawnie zinterpretowane. Jeżeli nie musisz stosować innego stylu znaczników, najlepiej używać tego sposobu.
Musisz używać tych znaczników, jeżeli stosujesz XML w PHP, ponieważ XML korzysta z krótkich znaczników otwierających.
Krótkie znaczniki otwierające (w stylu SGML) Krótkie znaczniki otwierające wyglądają w następujący sposób: To najkrótsza z możliwych opcji. Jeżeli często przełączasz się pomiędzy HTML i PHP,
styl ten może kusić mniejszą liczbą uderzeń w klawiaturę. Jednak cena stosowania tych znaczników może być wysoka. Musisz wykonać jedną z trzech czynności, aby PHP rozpoznawał takie znaczniki:
1. Wybierz opcję -enable-short-tags w trakcie konfigurowania przed kompilacją PHP.
2. Uaktywnij ustawienie short_open_tag w pliku php.ini. Musisz je wyłączyć, aby używać XML z PHP. 3. Użyj funkcji short_tags ( ) .
Krótkie znaczniki nie były obsługiwane przez wersję beta PHP 4. Zmusiło to wielu programistów do konwersji plików do postaci zgodnej ze znacznikami kanonicznymi, być
może tylko tymczasowej.
Rozdział 4. » Dodajemy PHP do HTML__________________________________71^
Znaczniki w stylu ASP Znaczniki w stylu ASP wyglądaj ą następująco: <% *>
Użytkownicy FrontPage często wybierają ten rodzaj znaczników. Aby można było ich używać, należy włączyć opcję konfiguracyjną w pliku php.ini. Oczywiście jeżeli używasz znaczników w stylu ASP i rozszerzenia .asp (np. konwertując witrynę z ASP do PHP), musisz wyłączyć ASP na serwerze IIS.
Znaczniki skryptu HTML Znaczniki takie wyglądająnastępująco:
Mimo że są one efektywne i rozwiązują problemy z FrontPage, mogą być niewygodne w niektórych sytuacjach, na przykład w krótkich sekwencjach używających zmiennych. Bądź szczególnie ostrożny, jeżeli strona zawiera kod JavaScript, ponieważ znaczniki zamykające skrypty są bardzo niejednoznaczne. Najlepiej używać znaczników skryptu HTML do dosyć obszernych bloków kodu PHP.
Witaj świecie Jesteśmy gotowi do napisania pierwszego programu w PHP. Otwórz nowy plik w ulubionym edytorze i wpisz:
Pierwszy program w PHP
Większość przeglądarek nie wymaga niczego poza sekcją PHP. Jednak dobrym pomysłem jest stosowanie kompletnej struktury HTML, do której wbudowujemy PHP. Jeżeli nie uzyskasz czegoś podobnego do rysunku 4.1, najprawdopodobniej zaistniał jakiś błąd podczas konfiguracji lub instalacji.
Przeczytaj jeszcze raz rozdział 3., opisujący instalację, i rozdział 31., traktujący o opcjach konfiguracyjnych. W rozdziale 15. rozpoznamy niektóre częste problemy i opiszemy wskazówki na temat uruchamiania programów.
Część l » Podstawy PHP
72
Rysunek 4.1.
Pierwszy skrypt PHP
Każdy, kto programuje od jakiegoś czasu, może być znudzony takim obowiązkowym skryptem. Jeżeli należysz do tej grupy ludzi, spróbuj dopisać do przedstawionego powyżej skryptu wiersz z funkcją phpinfo(). W rozdziale 31. wyjaśnimy dokładnie zawartość tej tabeli, a w tej chwili możesz to traktować jako testowanie instalacji.
Wejście i wyjście z trybu PHP Skrypt PHP składa się z trybu PHP lub HTML. Nie ma stanów pośrednich. Wszystko
w środku znaczników PHP jest kodem PHP, wszystko na zewnątrz znaczników PHP
jest czystym HTML.
Możesz błyskawicznie przełączać się do trybu PHP na tak długo i tak często, jak potrzeba. Na przykład:
Zauważ, że wiersze wykonywane w pierwszym bloku PHP, w tym wypadku przypisanie zmiennej, ciągłe obowiązują w drugim bloku. W następnym rozdziale opiszemy, co dzieje się ze zmiennymi, gdy wchodzisz i wychodzisz z bloku PHP.
Rozdział 4.
»
Dodajemy
PHP do
HTML__________________________________73
Dołączanie plików Innym sposobem na dodanie kodu PHP do HTML jest umieszczenie kodu w oddzielnym pliku i wywołanie go za pomocą funkcji include. Na przykład plik o nazwie dziewczyna.inc zawiera tylko:
Plik ten jest używany na stronie WWW w następujący sposób: Wyznanie
«
Daj mi swe usta, weź mnie w ramiona.
Niech się przekonam, ile słodyczy jest w słowie ""
Wynik pokazano na rysunku 4.2 (jeżeli twoje uczucia się zmienią, wystarczy zmienić jedną zmienną w pliku dziewczyna.inc). Rysunek 4.2.
Wynik dołączenia pliku*
Funkcja include przekazuje po prostu zawartość pliku jako tekst. Wielu użytkowników myśli, że skoro funkcja include jest wykonywana w bloku PHP, dołączany tekst jest również w trybie PHP. Nieprawda! Serwer przełącza się w tryb HTML przy dołączaniu każdego pliku i po cichu wraca do trybu PHP na jego końcu. Jeżeli usuniesz znaczniki PHP z pliku dziewczyna.inc w następujący sposób: $dziewczyna="Ilona";
print
("$dziewczyna");
treść pliku pojawi się w przeglądarce (a jeśli Ilona zna PHP...).
' Fragment piosenki zespołu „Wały Jagiellońskie".
74__________________________________________Część l
»
Podstawy PHP
Aby upewnić się, że nie zdarzy się taka sytuacja, należy zapamiętać, że każda część dołączanego pliku, która ma być wykonana jako PHP, musi być opatrzona prawidłowymi znacznikami PHP. Niektórzy w takich sytuacjach używają konstrukcji require zamiast funkcji include,
jednak include jest w większości przypadków mniej restrykcyjne. Z drugiej strony require jest wykonywane szybciej. Konstrukcje te są opisane w rozdziale na temat funkcji. Ponieważ include tylko przekazuje tekst, a nie kod PHP, może być stosowane do wstawiania fragmentów HTML. Możesz np. umieścić informację o prawach autorskich w pliku tekstowym i używać na każdej stronie funkcji include. Spowoduje to, że uaktualnianie informacji o prawach autorskich jest szybsze i mniej nużące.
Podsumowanie PHP łatwo można wbudowywać w istniejący kod HTML. Możesz użyć dowolnej ulubionej metody tworzenia HTML, a następnie dodać sekcje PHP. Dodany kod PHP może wykonywać wiele zadań, od wypisania liczby, aż do stworzenia sporego fragmentu kodu. Każdy blok PHP, dowolnej długości, jest ograniczony znacznikami. Istnieje kilka stylów znaczników PHP; początkujący użytkownicy powinni raczej używać znaczników kanonicznych. Możesz również włączać pliki PHP używając funkcji include ( ) lub require ( ) , lecz ich zawartość nie jest traktowana jako PHP, chyba że otoczysz ją znacznikami PHP.
Rozdział 5.
Składnia, zmienne i wyświetlanie W tym rozdziale: 4 Podstawowe zasady pisania kodu PHP •* Zapamiętywanie danych w zmiennych + Wyświetlanie wyników na stronie WWW W rozdziale tym opiszemy podstawy składni PHP i zasady, jakich musi się trzymać dobrze napisany kod PHP. Opiszemy sposób użycia zmiennych do zapamiętywania i odczytywania informacji w czasie wykonywania skryptu. Na koniec pokażemy najprostszy sposób wyświetlania tekstu w przeglądarce użytkownika.
PHP wiele wybacza Pierwszą i najważniejszą rzeczą, jaką można powiedzieć o języku PHP, jest to, że próbuje wybaczać możliwie wiele. Języki programowania coraz mniej rygorystycznie podchodzą do składni. Ścisłe stosowanie składni pomaga upewnić się, że napisany kod jest dokładnie tym, o czym myślałeś. Jeżeli napisałeś program sterujący reaktorem atomowym, ale zapomniałeś przypisać wartość zmiennej, to lepiej, że program zostanie odrzucony. Filozofia projektu PHP zdecydowanie różni się od takiego podejścia. Ponieważ PHP zrodził się jako narzędzie do tworzenia szybkich i prostych stron WWW, kładzie nacisk na wygodę programisty, a nie na poprawność kodu. Zamiast zmuszać programistę do dodatkowej pracy przy określaniu, co oznacza dany fragment kodu, PHP wymaga tylko minimum i próbuje orientować się, co autor miał na myśli. Z tego powodu nie potrzebuje konstrukcji językowych takich, jak deklarowanie zmiennych.
76__________________________________________Część
l
»
Podstawy
PHP
Jednak PHP nie potrafi czytać w twoich myślach, zakłada minimalny zestaw zasad, któ-
re muszą być zastosowane. Jeżeli zamiast świetnej strony WWW zobaczysz w przeglądarce komunikat „parse error", oznacza to, że złamałeś zasady i PHP musiał się poddać
podczas analizowania twojej strony.
HTML to nie PHP Drugą ważną zasadą jest to, że składnia PHP odnosi się tylko do fragmentów strony zawierających PHP. Ponieważ PHP jest wbudowany w dokumenty HTML, każda część takiego dokumentu jest interpretowana jako PHP lub HTML w zależności od tego, czy znajduje się pomiędzy znacznikami PHP, czy nie. Składnię PHP stosuje się tylko do PHP, więc zakładamy, że do końca tego rozdziału
mamy cały czas aktywny tryb PHP; większość fragmentów kodu należy wbudować w stronę HTML i otoczyć odpowiednimi znacznikami.
Składnia PHP bazuje na C Składania PHP bazuje na języku C. Jeżeli jesteś jednym z tych szczęśliwców znających
C, to dla ciebie bardzo wygodna sytuacja. Jeżeli nie jesteś pewien, jak powinno być zapisane jakieś wyrażenie, spróbuj najpierw napisać je w C (jeżeli nadal nie działa, zajrzyj do podręcznika). Dalsza część przeznaczona jest dla czytelników, którzy nie znają C (programiści C mogą przejrzeć nagłówki oraz przeczytać dodatek dla nich napisany).
PHP nie przejmuje się odstępami Przez odstępy rozumiemy wszystkie znaki niewidoczne na ekranie, włączając spacje, tabulacje, znaki końca wiersza. To, że PHP nie przejmuje się odstępami, nie oznacza, że odstępy nigdy nie są znaczące (są niezbędne do oddzielania „słów" języka PHP). Można stwierdzić, że nie ma znaczenia liczba odstępów w wierszu, jeden odstęp jest tak samo dobry jak kilka. Każde przytoczone poniżej wyrażenie przypisuje sumę 2 + 2 do zmiennej Sfour: $four = 2 + 2 ; Sfour =22
Sfour 2 +
2;
"
;
// pojedyncze odstępy // odstępy i tabulacje
// wiele linii
Używanie znaku końca wiersza jest bardzo wygodne, ponieważ nigdy nie trzeba się starać, aby wyrażenie zmieściło się w jednym wierszu.
^^fe.
Rozdział 5. » Składnia, zmienne i wyświetlanie__________________________ 77
PHP jest czasami wrażliwy na wielkość liter Przeczytawszy wcześniej, że PHP nie jest wybredny, pewnie będziesz zaskoczony, że czasami jest jednak wrażliwy na wielkość liter (różnica pomiędzy małymi i wielkimi literami ma dla niego znaczenie). Wielkość liter ma znaczenie dla wszystkich zmiennych. Jeżeli wstawisz następujący kod do strony HTML:
?>
$capital = 67; print("Zmienna capital ma wartość $capital "); print("Zmienna CaPiTal ma wartość $CaPiTal ");
to oglądając wynikową stronę zobaczysz: Zmienna capital ma wartość 67 Zmienna CaPiTal ma wartość
Ponieważ różne wielkości liter spowodowały wygenerowanie dwóch różnych zmiennych (standardowe ustawienia nie spowodowały wygenerowania błędu „nieprzypisana zmienna"; więcej informacji znajdziesz w części „Nieprzypisane zmienne"). Inaczej niż w C, nazwy funkcji i podstawowe konstrukcje języka (if, then, else, while itp.) ignoruj ą wielkość liter.
Instrukcje to wyrażenia zakończone średnikiem Poniżej przedstawiamy typową instrukcję w PHP, w tym przypadku przypisuje ona ciąg znaków do zmiennej o nazwie $greeting: Sgreeting = "Witaj w P H P ! " ;
Poniżej opiszemy, w jaki sposób wyrażenia są budowane z mniejszych fragmentów i jak interpreter PHP realizuje przetwarzanie wyrażeń (jeżeli wyrażenie i instrukcje nie przysparzają ci problemu, możesz opuścić ten fragment). Najmniejszymi fragmentami wyrażeń w PHP są niepodzielne elementy, takie jak liczby (3.14159), ciągi ("dwa"), zmienne (Sdwa), stałe (TRUE) i słowa kluczowe składni PHP (if, else itd.). Są one oddzielone od siebie odstępami lub innymi znakami specjalnymi, takimi jak nawiasy okrągłe i klamrowe. Następny, bardziej skomplikowany składnik PHP to wyrażenie, które jest dowolną kombinacją elementów mających jakąś wartość. Zarówno pojedyncza liczba, jak i zmienna są wyrażeniami. Proste wyrażenia mogą być łączone w złożone, zwykle poprzez wstawienie pomiędzy nie operatora, (np.: 2 + ( 2 + 2 ) ) lub użycie funkcji (np.: power_
of (2*3, 3*2)). Operatory działające na dwóch argumentach są wstawiane pomiędzy, natomiast funkcje pobierają dane z nawiasów następujących bezpośrednio po nazwie funkcji. Dane te (parametry) rozdziela się przecinkami.
J78__________________________________________Część l
»
Podstawy PHP
Obliczanie wyrażeń Jeżeli interpreter PHP napotka w tekście wyrażenie, natychmiast oblicza jest jego wartość. Oznacza to, że PHP oblicza wartości najmniejszych części wyrażenia i łączy ze sobą wartości połączone operatorami lub wywoływanymi funkcjami, dopóki nie zostanie uzyskana wartość całego wyrażenia. Kolejne kroki obliczania wartości wyrażenia wyglądają następująco: $wynik = 2 * 2 + 3 * 3 + 5;
( = 4 + 3 * 3 + 5 ) (=4+9+5) (= 13 + 5) (= 18)
// kolejne kroki obliczania
Wynik działań, liczba 18, jest zapisany do zmiennej $wynik.
Priorytety, łączenie i kolejność obliczeń Przy wyliczaniu wyrażeń w PHP stosuje się dwa rodzaje zasad: sposób łączenia podwyrażeń i kolejność ich obliczania. W przykładzie, który powyżej przedstawiliśmy, mnożenia były wykonywane wcześniej niż dodawania, co ma wpływ na końcowy wynik.
Sposób, w jaki operatory grupują wyrażenia jest nazywany priorytetem operatorów. Operatory o wyższym priorytecie wygrywają w „łapaniu" wyrażeń umieszczonych
obok nich. Jeżeli chcesz, możesz zapamiętać te priorytety, np. „*" ma wyższy priorytet od „+" (opiszemy to dokładniej w dalszych rozdziałach). Jeżeli nie jesteś pewien kolejności wykonania operacji, zawsze możesz użyć nawiasów do grupowania wyrażeń. Na przykład: $wynikl = 2 + 3 * 4 + 5 Swynik2 = (2 + 3) * (4 + 5)
//=19 // = 45
Priorytety operatorów usuwają większość niejednoznaczności przy łączeniu podwyrażeń, jednak problemy w interpretacji kolejności obliczania wyrażeń z takim samym priorytetem pozostają. Na przykład: $ile = 3 . 0 / 4 . 0 / 5 . 0 ;
Wynik może być 0,15 lub 3,75 w zależności od tego, który operator dzielenia pierwszy „złapie" liczbę 4. W podręczniku znajduje się wyczerpująca lista zasad łączenia, jednak najważniejszą z nich jest łączenie podwyrażeń od lewej do prawej. Zgodnie z tym nasze wyrażenie ma wartość 0,15, ponieważ pierwszy z lewej operator dzielenia będzie wykonany najpierw.
Ostatnim problemem jest kolejność obliczeń, co nie jest tożsame z łączeniem wyrażeń. Dla przykładu spójrzmy na następujące wyrażenie: 3*4 +
5*6
Wiemy, że mnożenie wykonywane jest przed dodawaniem, jednak nie wiemy, które mnożenie zostanie wykonane pierwsze. Zwykle nie będziesz musiał przejmować się
Rozdział 5.
»
Składnia, zmienne i wyświetlanie_____________________________79
kolejnością, ponieważ w większości przypadków nie wpływa na wynik. Można tworzyć dziwaczne wyrażenia, w których wynik zależy od kolejności obliczeń, zwykle wykonując przypisania w podwyrażeniach. Na przykład: Sha = ($to = Stamto + 5) + (Stamto = Sto + 3); // ŹLE
Nie pisz w ten sposób! PHP może, ale nie musi mieć zdefiniowanej kolejności obliczania wyrażeń, jednak nie powinieneś na tym polegać (jedynym dozwolonym użyciem obliczania od lewej do prawej jest „skracanie" wyrażeń logicznych, które opiszemy
w rozdziale 7.).
Wyrażenia i typy Zwykle programiści są ostrożni przy dobieraniu typów wyrażeń dla operatorów lub funkcji. Najczęściej występujące to wyrażenia matematyczne (używające operatorów
matematycznych do działań na liczbach), logiczne (obliczające wyrażenia typu prawda lub fałsz za pomocą operatorów and i or) lub operacje na ciągach (za pomocą operatorów i funkcji tworzących ciągi znaków). Rozważmy poniższe wyrażenie, które umyśl-
nie miesza typy podwyrażeń: 2 + 2 * "nonsens" + TRUE
Zamiast komunikatu o błędzie pojawi się liczba 3 (możesz potraktować to jako zagadkę; w następnym rozdziale wyjaśnimy, co się stało).
Przypisywanie wyrażeń Często używa się wyrażeń, w których do zmiennej przypisywany jest wynik jakiegoś wyrażenia. Ma ono postać nazwy zmiennej (poprzedzonej znakiem S), następnie pojedynczego znaku równości i obliczanego wyrażenia. Na przykład: Sosiem -
2
*
(2*2}
Wyrażenie to przypisze spodziewaną wartość do zmiennej $osiem.
Należy również pamiętać, że wyrażenia przypisania same w sobie są wyrażeniami i posiadaj ą wartość! Wartość ta jest wartością zmiennej po wykonaniu przypisania. Możesz więc użyć przypisania w środku bardziej skomplikowanego wyrażenia. Jeżeli wykonasz następujące wyrażenie $dziesiec = ($dwa = 2) 4- (Sosiem = 2 * ( 2 * 2 ) )
do każdej ze zmiennych zostanie przypisana wartość zgodna z jej nazwą. Podsumowując, instrukcją PHP jest każde wyrażenie zakończone średnikiem. Jeżeli
wyrażenie porównamy do wyrazów, to instrukcja stanowi pełne zdanie, a średnik jest kropką na jego końcu. Każda sekwencja prawidłowych instrukcji opatrzona znacznikami PHP stanowi program.
80_______________________________________
Część l » Podstawy PHP
Powody używania wyrażeń i instrukcji
Są dwa powody pisania wyrażeń: uzyskanie ich wartości oraz efektu ubocznego. War-
tością wyrażenia jest to, co może być przekazane do bardziej skomplikowanych wyrażeń. Efekt uboczny to wszystko, co zdarzyło się w czasie obliczania wyrażenia. Najbardziej
typowymi efektami ubocznymi to przypisanie wartości do zmiennej, zmiana wartości
zmiennej, wypisanie czegoś na ekranie lub wykonanie trwałej zmiany w środowisku
programu (np. zmiany w bazie danych).
Mimo, że instrukcje są wyrażeniami, nie są włączane w bardziej skomplikowane wyrażenia. Oznacza to, że jedynym powodem pisania instrukcji jest efekt uboczny! Można więc pisać poprawne, ale całkowicie nieużyteczne instrukcje, jak na przykład druga z poniższych: print("Witaj");
2*3+4;
// efektem ubocznym jest wydruk na ekranie
// bezużyteczne — brak efektu ubocznego
$value_num=3M + 5; // efektem ubocznym jest przypisanie
store_in_database(49.5); // efektem ubocznym jest zapis w bazie
Bloki Mimo że instrukcji nie można łączyć tak jak wyrażeń, można zawsze umieścić sekwen-
cję instrukcji tam, gdzie spodziewana jest jedna instrukcja, poprzez otoczenie grupy instrukcji nawiasami klamrowymi.
Konstrukcja if w PHP ma wyrażenie warunku (w okrągłych nawiasach), po którym następuje instrukcja wykonywana, jeżeli wartością warunku jest TRUE. Jeżeli chcesz, aby wykonane zostało kilka instrukcji, musisz wstawić w to miejsce sekwencję otoczoną
nawiasami klamrowymi. Poniższe fragmenty kodu (wypisujące uspokajające informacje, że 1+2 to nadal 3) są równoważne: if (3 == 2 + 1)
print!" Na szczęście to jeszcze działa jak myślałem ") ; if (3 == 2 + 1) f print(" Na szczęście to jeszcze"); print (" działa jak myślałem "); )
Możesz umieścić w bloku dowolny rodzaj instrukcji, nawet kolejną instrukcję if,
która będzie miała swój blok instrukcji. Oznacza to, że instrukcja if może zawierać inną instrukcję if. Takie zagnieżdżanie jest możliwe bez szczególnych ograniczeń liczby poziomów.
Komentarze Komentarz to fragment programu przeznaczony tylko dla programistów, nie dla interpretera. Pierwszą czynnością, jaką wykonuje analizator języka, jest usunięcie komentarzy, więc nie mają one wpływu na działanie programu. Komentarze są nieocenioną
Rozdział 5.
»
Składnia, zmienne i wyświetlanie___________________________81
pomocą dla innej osoby, czytającej twój kod i starającej się zorientować, o czym myślałeś, gdy pisałeś ten fragment. Często tąosobąjesteś ty sam, po kilku tygodniach bądź miesiącach od napisania programu. PHP czerpał inspirację z języków programowania C, Perl oraz skryptów powłoki Unix. W efekcie PHP zapewnia kilka sposobów komentowania pochodzących z tych języków. Style te mogą być dowolnie mieszane w kodzie PHP.
Komentarze wielowierszowe w stylu C Wielowierszowe komentarze są identyczne jak w C. Komentarz rozpoczyna się parą
znaków / * i kończy się znakami * /. Na przykład: /*
To jest komentarz w PHP */
Trzeba pamiętać, że komentarzy nie można zagłębiać. Nie możesz umieścić jednego komentarza w drugim. Jeżeli spróbujesz to zrobić, komentarz zakończy się na */, a reszta tekstu, która miała być komentarzem, będzie interpretowana, co najprawdopodobniej spowoduje błąd. Na przykład: /* Ten komentarz spowoduje /* błąd na ostatnim wyrazie tego */ zdania V
Łatwo jest zrobić coś takiego nieświadomie, zwykle gdy próbujesz wyłączyć fragment kodu przez jego zakomentowanie.
Komentarze jednowierszowe: # i // Oprócz wielowierszowych komentarzy / * . . . * / możesz na dwa sposoby umieszczać komentarze rozciągające się do końca wiersza. Jeden sposób pochodzi z C++ i Java, drugi z Perl i skryptów powłoki systemowej. Komentarze w stylu skryptów powłoki rozpoczynają się od znaku #, natomiast komentarze w stylu C++ od //. Oba te sposoby komentowania powodują, że reszta bieżącego wiersza jest traktowana jako komentarz. tt To jest komentarz t a to jest druga linia komentarza // To również jest komentarz. Oba style komentują tylko // jedna linię. Więc ostatnie słowo tego zdania spowoduje błąd.
Uważny czytelnik może spostrzec, że jednowierszowe komentarze nie są zgodne z tym, co powiedzieliśmy wcześniej o ignorowaniu odstępów. Jeżeli zastąpisz jedną ze spacji
w jednowierszowym komentarzu znakiem nowego wiersza, kod przestanie działać. Bardziej precyzyjne jest określenie, że po usunięciu komentarzy kod PHP jest niewrażliwy na liczbę i rodzaj odstępów.
82__________________________________________Część l
»
Podstawy PHP
Zmienne Główną metodą przechowywania informacji w środku programu PHP jest użycie zmiennych, które są sposobem na nazwanie i zapamiętanie wartości używanych później. Poniżej przedstawimy najważniejsze informacje o zmiennych PHP (szczegółowy opis w dalszej części). * Wszystkie zmienne są rozpoczynane znakiem $. * Wartością zmiennej jest wynik ostatniego przypisania. * Wartość zmiennych przypisuje się przy użyciu operatora = ze zmienną po lewej stronie, a wyrażeniem po prawej. * Zmienne nie wymagają deklaracji przed użyciem.
* Zmienne nie mają określonego typu; jest on określany typem bieżącej wartości. * Zmienne użyte przed przypisaniem maj ą wartości domyślne.
PHP skorzystał ze stylu zmiennych Perl Wszystkie zmienne w PHP rozpoczynają się znakiem „$" jak zmienne skalarne w języku Perl, podobnie się też zachowują (nie wymagają deklaracji typu, można się do nich odwoływać przed przypisaniem itp.). Hakerzy Perl nie muszą nic więcej robić poza spojrzeniem na nagłówki tej części.
Po początkowym znaku „$" zmienna może składać się z liter (małych bądź wielkich), cyfr (O - 9) oraz podkreślenia („_")• Pierwszy znak po $ nie może być cyfrą.
Deklarowanie zmiennych Ten podpunkt umieściliśmy w tym miejscu, ponieważ programiści piszący w innych językach mogą go szukać. W językach takich jak C, C++ i Java programista musi zadeklarować nazwę i typ zmiennej przed jej użyciem. Ponieważ w PHP typy są związane z wartościami, a nie ze zmiennymi, deklaracja nie jest konieczna; pierwszym krokiem użycia zmiennej jest przypisanie jej wartości.
Przypisywanie zmiennym wartości Przypisanie wartości do zmiennej jest proste: napisz nazwę zmiennej, następnie pojedynczy znak =, a następnie wyrażenie, którego wartość chcesz przypisać do zmiennej. Śpi = 3 + 0 . 1 4 1 5 9 ; / / w p r z y b l i ż e n i u
Zauważ, że przypisujesz wynik wyrażenia, a nie samo wyrażenie. Po wykonaniu wyrażenia nie ma sposobu na stwierdzenie, że wartość $pi powstała z dodania dwóch liczb.
Rozdział 5. » Składnia, zmienne i wyświetlanie___________________________83
Zmiana wartości zmiennych Nie ma żadnej różnicy pomiędzy przypisywaniem wartości za pierwszym razem a późniejszą zmianą wartości. Nie zmienia tego nawet fakt przypisywania różnych typów. Poniższy przykład jest całkowicie prawidłowy: $wart_num = "To powinna być liczba mam nadzieje, że będzie zmieniona"; $wart_num = 5;
Jeżeli druga instrukcja będzie wykonana bezpośrednio po pierwszej, pierwszy wiersz nie będzie miał znaczenia.
Nieprzypisane zmienne Wiele języków programowania sprzeciwia się używaniu zmiennej przed przypisaniem jej wartości. Inne pozwalają na to, ale mogą odwoływać się do losowej zawartości obszaru pamięci. W PHP domyślne ustawienie raportowania błędów pozwala na używanie zmiennych bez wcześniejszego przypisania. Zmienne będą miały rozsądne domyślne
wartości.
Jeżeli chcesz dostawać ostrzeżenie o nieprzypisanych zmiennych, powinieneś zmienić poziom raportowania błędów na 15. z domyślnego 7. Można to zrobić przez umieszczenie na początku skryptu wyrażenia error_reporting(i5) lub zmienić to ustawienie w pliku php.ini (patrz rozdział 32.).
Wartości domyślne Zmienne w PHP nie mają ustalonego typu, zmienne „nie wiedzą wcześniej", czy będą przechowywały liczby, czy ciągi znaków. W jaki sposób znana im jest wartość domyśl-
na, skoro nie były jeszcze przypisywane?
Odpowiedź jest taka sama jak przy przypisywaniu zmiennych: typ zmiennej jest ustala-
ny w zależności od kontekstu, w którym jest użyta. W sytuacjach gdy spodziewamy się liczby, będzie ona liczbą, w innej sytuacji będzie ciągiem znaków. Jeżeli kontekst wymaga uznania nieprzypisanej zmiennej za liczbę, zmienna taka będzie traktowana, jakby miała wartość 0. W innym kontekście, w którym spodziewamy się ciągu znaków, będzie to ciąg pusty (o długości 0).
Sprawdzanie przypisania za pomocą IsSet Ponieważ zmienne nie muszą być przypisane przed użyciem, w niektórych sytuacjach powinieneś wiedzieć, czy zmienna była przypisana, czy nie. W PHP jest funkcja IsSet, która sprawdza, czy zmienna ma przypisaną wartość. Poniższy fragment kodu pokazuje, że nieprzypisana zmienna jest rozróżniana od zmiennej, której nadano wartość domyślną:
JJ4_______________________________________Część l » Podstawy PHP ?set_var - 0;
// set_var posiada wartość
// never_set nie posiada
print ("set_var posiada wartość: 5set_var "); print ("never_set posiada wartość: $never_set "); if ($set_var -= $never_set)
print("set_var jest równe never_set "); if (IsSet($set_var)) print("set_var posiada przypisana wartość "); else
print("set_var nie posiada przypisanej wartości "}; if (IsSet($never_set))
print("never_set posiada przypisana wartość "); else
print("never_set nie posiada przypisanej wartości ");
Wynik wykonania tego fragmentu jest następujący: set_var posiada wartość: O
never_set posiada wartość: set_var jest równe never_set set__var posiada przypisaną wartość never_set nie posiada przypisanej wartości
Zmienna $never__set nie była nigdzie przypisana, więc gdy spodziewany był ciąg znaków, dawała pusty ciąg znaków (w instrukcji print), lub zero, gdy spodziewana była
liczba (jak w porównaniu sprawdzającym, czy zmienne są takie same). Jednak funkcja IsSet mogła określić różnicę pomiędzy $set_var i $never_set.
Przypisanie wartości do zmiennej nie jest nieodwracalne, funkcja unset {} przywraca zmienną do postaci nieprzypisanej (np. po wykonaniu unset ($set_var) zmienna
$set_var nie będzie miała przypisanej wartości, niezależnie od wcześniejszych przypisań).
Zasięg zmiennych Zasięg jest technicznym terminem zasad określających, kiedy nazwa (zmienna lub funkcja) ma to samo znaczenie w dwóch różnych miejscach i w jakich sytuacjach dwie identyczne nazwy mogą odwoływać się do różnych rzeczy.
W PHP każda zmienna, która nie jest w ciele funkcji, posiada zasięg globalny i rozciąga się na cały przebieg wykonania. Inaczej mówiąc, jeżeli przypiszesz zmienną na
początku pliku PHP, nazwa tej zmiennej będzie miała takie samo znaczenie i jeżeli nie zostanie powtórnie przypisana, będzie miała taką samą wartość w całym kodzie (oprócz ciała funkcji).
Przypisanie wartości nie wpływa na wartości zmiennych o takiej samej nazwie w innych plikach PHP, a nawet na kolejne użycia tego samego pliku. Załóżmy, że mamy
dwa pliki start.php i nastepny.php, które zwykle są odwiedzane w takiej kolejności
przez użytkowników. Załóżmy również, że na początku pliku start.php znajduje się wiersz $username = "Jan Kowalski";
który jest wykonywana w niektórych sytuacjach. Możesz założyć, że po ustawieniu tej zmiennej w start.php będzie ustawiona również w nastepny.php, jednak tak nie jest. Za każdym razem gdy strona jest wykonywana, zmienne są przypisywane, a na końcu strony znikają.
Rozdział 5. » Składnia, zmienne i wyświetlanie___________________________85
Funkcje i zasięg zmiennych Poza ciałem funkcji zasięg zmiennych jest dosyć jasny: dla każdego wykonania pliku PHP po prostu przypisujemy zmiennej wartość i wartość ta będzie dostępna. Jeszcze nie omawialiśmy sposobu definiowania funkcji, jednak opiszemy zachowanie się zmiennych. Zmienne przypisane w funkcji działają jako zmienne lokalne funkcji. Jeżeli nie zadeklarujesz funkcji w odpowiedni sposób, nie będziesz miał dostępu do zmiennych globalnych, nawet jeżeli były zdefiniowane w tym samym pliku (zasięg zmiennych w funkcjach omówimy w rozdziale 11.).
Oczywiście w wielu sytuacjach będziesz chciał przechować informacje dłużej niż tylko na czas wygenerowania jednej strony. Jest kilka sposobów na zrealizowanie tego zadania, opiszemy je w dalszej części książki. Możesz przesyłać dane między stronami, używając zmiennych GET i POST (rozdział 12.), zapisywać dane w bazie danych (II część książki), przypisać do sesji użytkownika przy użyciu nowego mechanizmu PHP obsługującego sesje (rozdział 25.) lub zapisać na dysku użytkownika używając mechanizmu cookie (rozdział 26.).
Możesz dowolnie zmieniać tryby pracy Jedno z naszych pierwszych pytań na temat zasięgu brzmiało: czy zmiany trybu pracy z PHP na HTML i odwrotnie przetrwają. Jeżeli mamy plik wyglądający następująco: "); ?>
czy mamy oczekiwać, że przypisanie do $username przetrwa do drugiego obszaru
PHP. Odpowiedź brzmi: tak. Zmienne istnieją przez cały proces wykonania PHP (inaczej mówiąc, przez cały proces tworzenia strony wysyłanej do użytkownika). Jest to objaw generalnej zasady PHP, która mówi, że jedynym celem znaczników jest wskazanie maszynie PHP, czy fragment kodu należy interpretować jako tekst, czy przesłać jako nietknięty HTML. Możesz dowolnie używać znaczników, aby przełączać się pomiędzy trybami, gdy tego potrzebujesz.
86__________________________________________Część l
«
Podstawy PHP
Wyjście Większość konstrukcji języka PHP jest wykonywana w sposób ukryty; nie piszą one nic na wyjściu. Jedynym sposobem, aby wbudowany kod PHP wyświetlił cokolwiek
w przeglądarce użytkownika jest użycie funkcji piszącej coś do wyjścia lub użycie instrukcji print.
Echo i print Dwoma podstawowymi konstrukcjami drukującymi dane na wyjściu są echo i print. Ich status w języku jest nieco mylący, ponieważ są podstawowymi konstrukcjami języ-
ka, a nie funkcjami. Dzięki temu mogą być używane z nawiasami, albo bez nich (funkcje zawsze mają nazwę, po której następuje otoczona nawiasami lista parametrów).
Echo Najprostszym sposobem użycia funkcji echo jest wypisanie ciągu podanego jako argument, np.: echo "To będzie wyświetlone w oknie przeglądarki,";
lub echo ("To będzie wyświetlone w oknie przeglądarki.");
Oba te wyrażenia powodują wyświetlenie podanego zdania bez cudzysłowów (uwaga dla programistów C: myśl o połączeniu HTTP jak o „standardowym strumieniu wyjściowym" dla tych funkcji). Możesz podać wiele argumentów do wyrażenia echo bez nawiasów, rozdzielając je przecinkami: echo "To będzie wyświetlone", " w oknie przeglądarki.";
natomiast wersja z nawiasami nie przyjmie większej liczby argumentów: echo ("To spowoduje ", "błąd składniowy.");
Print Instrukcja print jest bardzo podobna do echo, ale: •* print przyj muj e tylko j eden argument; * print zwraca wartość wskazującą na to, czy udało się wykonanie instrukcji print.
Wartość zwracana przez print to l, gdy drukowanie zakończyło się sukcesem, i O, gdy się nie udało (rzadko się zdarza, że poprawna składniowo instrukcja print nie powiedzie się, jednak teoretycznie umożliwia sprawdzenie, czy np. przeglądarka użytkownika zerwała połączenie). Zarówno echo, jak i print są używane zwykle z ciągami znaków
Rozdział 5. » Składnia, zmienne i wyświetlanie_____________________________87^
jako argumenty, jednak elastyczność PHP w traktowaniu typów pozwala na pobranie dowolnego typu argumentu bez powodowania błędu. Poniższe wiersze wypisują dokładnie to samo: print("3.14159"); print(3.14159);
// drukuj ciąg
// drukuj liczbę
Technicznie rzecz biorąc, print w drugiej linii spodziewał się ciągu znaków jako argumentu, więc liczba zmiennoprzecinkowa została skonwertowana do ciągu, zanim print ją dostał. Jednak głównym efektem jest to, że zarówno print, jak i echo doskonale drukują liczby i ciągi znaków. Przez wzgląd na prostotę i jednolitość zwykle używamy print z nawiasami w naszych przykładach instrukcji.
Zmienne i ciągi Programiści C są przyzwyczajeni do używania funkcji print f, która pozwala na wklejenie wartości i wyrażeń do specjalnie sformatowanego ciągu. PHP posiada analogiczną funkcję (opiszemy ją w rozdziale 9.), możemy jednak uzyskać ten sam efekt, używając print (lub echo).
Fragment kodu: Sanimal = "Antylopa"; $animal_heads = 1;
$animal_legs = 4; print! "Sanimal ma $animal_heads głowę. "); print( "$animal ma $animal_legs nogi. ");
da następujący wynik: Antylopa ma l głowę.
Antylopa ma 4 nogi.
Wartości zmiennych umieszczonych w ciągu zostały wklejone do wyniku. Jest to użyteczna własność, która pozwala na szybkie tworzenie zawartości stron WWW, które zależą od wartości zmiennych. I to nie dzięki własnościom print interpretacja ciągów jest naprawdę magiczna.
Apostrofy kontra cudzysłowy PHP wykonuje wstępne przetworzenie ciągów otaczanych cudzysłowami (ciąg o "takiej" postaci) przed tworzeniem ich wartości. Zmienne są zamieniane na wartości (jak w poprzednim przykładzie). Aby sprawdzić, jak naprawdę są tworzone ciągi, rozważmy taki przykład: $animal = "Antylopa"; // $saved_string = "Zwierzę to $animal "; $animal - "Zebra"; // print("Zwierze to $animal "); // print($saved_string); //
pierwsze przypisanie zmiana wartości pierwsza linia wydruku druga linia wydruku
88__________________________________________Część
l
»
Podstawy
PHP
Jaki otrzymamy wynik? Przeglądarka wyświetli następujący wynik: Zwierzę to Zebra
Zwierzę to Antylopa
Stało się tak, ponieważ „Antylopa" została wklejona do ciągu $saved_string przed zmianą wartości zmiennej $ an ima l.
Oprócz wklejania wartości zmiennych do ciągów PHP zamienia niektóre kilkuznakowe sekwencje sterujące na wartości jednoznakowe. Najczęściej używanąjest sekwencja końca wiersza („\n"). W wierszu: "Pierwsza linia \n\n\n Czwarta linia"
PHP zmieni każdy „\n" na znak końca wiersza. Jeżeli obejrzysz źródło strony HTML, powinieneś zobaczyć kilka pustych wierszy w środku kodu (w oknie przeglądarki wszystko będzie w jednej linii; przeczytaj „HTML i końce wiersza" w dalszej części rozdziału). Ciągi otaczane apostrofami (na przykład 'takie'} zachowują się inaczej. PHP nie wykonuje wklejania zmiennych i przetwarza jedynie dwie sekwencje sterujące (możesz wstawić znak ' do środka ciągu, pisząc Y oraz \, pisząc \\). Oprócz tych dwóch wyjątków PHP interpretuje ciąg dosłownie. Jeżeli do ciągu wstawisz znak $ i wypiszesz go, w przeglądarce zobaczysz znak $. Takie traktowanie ciągów może być użyteczne, jeżeli chcesz na przykład wypisać ścieżkę w stylu Windows. Wyrażenie print('c:\newcode\php\myphp.php1);
wypisze ścieżkę tak, jak tego chcemy. Wersja z cudzysłowami zinterpretuje pierwszy backslash jako początek sekwencji sterującej i wstawi znak końca wiersza zaraz za 'c:'.
HTML i końce wierszy Częstym błędem popełnianym przez nowych programistów PHP (szczególnie tych z przeszłością C) jest próba złamania wiersza w przeglądarce wstawianiem znaku końca wiersza („\n") do ciągu. Aby zrozumieć, dlaczego to nie działa, należy zauważyć, że wyjście programu PHP (które zwykle ma postać kodu HTML, gotowego do wysłania przez Internet do przeglądarki) jest interpretowane przez przeglądarkę użytkownika. Większość przeglądarek podejmuje własne decyzje, w jaki sposób złamać linie tekstu, chyba że wymusimy to za pomocą znacznika . Znaki końca wiersza w ciągach będą umieszczone w źródle strony wysyłanej do użytkownika, ale zwykle nie dają widocznego efektu w wyglądzie tekstu na stronie WWW.
Podsumowanie Kod PHP jest zgodny z kilkoma zasadami składniowymi, w większości zapożyczonymi z języków C i Perl. Wymagania składniowe są minimalne; PHP zwykle próbuje wyświetlać wynik.
Rozdział 5. » Składnia, zmienne i wyświetlanie___________________________89
Kod PHP jest niezależny od liczby odstępów, w nazwach zmiennych są rozróżniane wielkie i małe litery. Wielkość liter nie ma znaczenia dla konstrukcji języka i nazw funkcji. Proste wyrażenia są łączone w większe za pomocą operatorów i wywołań funkcji. Wyrażenia zakończone średnikiem są instrukcjami. Zmienne są odróżniane po początkowym znaku S; do przypisania używany jest operator =. Nie ma potrzeby deklarowania typów; zmienne zawsze mają domyślne wartości w przypadku ich użycia przed pierwszym przypisaniem. Zmienne mają zasięg globalny oprócz ciała funkcji, w którym zmienne są lokalne, chyba że zdecydujemy inaczej. Najprostszą metodą wysłania danych na wyjście jest użycie funkcji echo lub print, które wypisują ciąg przekazywany jako argument. Są one dosyć użyteczne, szczególnie
w połączeniu z ciągami w cudzysłowach, które automatycznie modyfikują zmienne na ich wartości.
90
Część l » Podstawy PHP
Rozdział 6.
Typy w PHP W tym rozdziale: 4 Poznajemy sześć typów w PHP: integer, double, boolean, string, array i object 4 Tworzenie, czytanie, drukowanie i manipulacja obiektami różnych typów 4 Konwersja z jednego typu do innego
Wszystkie języki programowania mają jakiś rodzaj systemu typów, który definiuje różne
rodzaje wartości, jakie mogą pojawiać się w programie. Typy często korespondują
z różną reprezentacją bitową w pamięci komputera, jednak w wielu przypadkach programiści nie muszą myśleć o reprezentacji na poziomie bitów. System typów PHP jest prosty, wydajny, elastyczny; izoluje od niskopoziomowych szczegółów.
Rozdział ten opisuje podstawowe typy PHP (integer, double, boolean, string, array i object) i pokazuje, w jaki sposób są one odczytywane, drukowane, przypisywane do zmiennych
konwertowane i łączone. Rozdział ten stanowi zarówno przegląd, jak i podręcznik: zaznajomieni z programowaniem mogą go opuścić, mniej zaawansowani powinni przeczytać początkowe fragmenty; ale doń wracać, aby zgłębić te szczegóły, które nie wydawały się ważne za pierwszym razem.
Pierwsza zasada: nie przejmuj się PHP jest tak prosty, że nie musisz się martwić o typy zmiennych, ponieważ nie tylko nie wymaga określania typu zmiennych, ale także wykonuje wiele typowych konwersji za ciebie.
Brak deklaracji typów zmiennych Jak stwierdziliśmy w poprzednim rozdziale, nie ma potrzeby deklarowania typów zmiennych. W zamian programista może od razu przejść do przypisania i pozwolić PHP
zorientować się, jakiego typu jest przypisywane wyrażenie.
92__________________________________________Część l
*
Podstawy PHP
$first_number = 55.5;
$second_number = "To nie liczba";
Automatyczna konwersja typów PHP automatycznie konwertuje typy, gdy jest to potrzebne. Jak inne nowoczesne języki programowania, PHP dokona odpowiedniej konwersji, gdy np. wykonujemy operację matematyczną na różnych typach numerycznych. Wynik wyrażenia $pi = 3 + 0 . 1 4 1 5 9
będzie liczbą zmiennoprzecinkową (double), z liczbą 3 niejawnie skonwertowaną na liczbę zmiennoprzecinkową przed wykonaniem dodawania.
Typy nadawane poprzez kontekst PHP idzie dalej, niż większość języków programowania, w stosowaniu automatycznej
konwersji typów. Rozważmy przykład: Ssub = s u b s t r ( 1 2 3 4 5 , 2 , 2 ) ; p r i n t ( " C i ą g to $ s u b < B R > " ) ;
Funkcja substr jest zaprojektowana do pobierania fragmentu ciągu, od punktu startowego i długości określanej przez ostatnie dwa parametry funkcji. Zamiast operować na ciągu znaków, wpisaliśmy liczbę 12345. Co się stało? Nie nastąpił błąd, a w przeglądarce dostaliśmy wynik: Ciąg to 34
Ponieważ substr spodziewa się ciągu znaków, a nie liczby, PHP skonwertuje dla nas liczbę 12345 do postaci ciągu znaków '12345'. Z powodu automatycznej konwersji typów ciężko jest zmusić PHP do zwrócenia błędu typu. Jednak programiści PHP muszą upewnić się, że konwersje niepowodujące błędów
nie dadzą nieoczekiwanych wyników.
Typy w PHP PHP posiada tylko sześć typów danych: integer, double, boolean, string, array i object. •* integer to liczby całkowite bez przecinka, na przykład 4 9 5 . • Double to liczby zmiennoprzecinkowe: 3 .14159 lub 4 9 . 0 . •* Boolean ma tylko dwie wartości: TRUE i FALSE. •* String to ciąg znaków, np.'PHP 4.0 obsługuje operacje na ciągach'.
• Array to nazwana i zindeksowana kolekcja wartości.
Rozdział 6.
» Typy w PHP_______________________________________93
•* Object to egzemplarz zdefiniowanej przez programistę klasy, która agreguje wartości i funkcje na nich operujące.
Pierwsze pięć z nich to typy proste, natomiast ostatnie dwa są złożone. Typy złożone mogą zawierać dowolne wartości dowolnych typów, w przeciwieństwie do typów prostych. W tym rozdziale nie będziemy się zagłębiać w typy złożone, zajmiemy się nimi w oddzielnym rozdziale.
Typy proste Proste typy danych powinny być znane dla wszystkich, który już wcześniej programowali.
Jedyną rzeczą, jaka zaskoczy programistów C, jest niewielka liczba typów.
Wiele języków programowania ma kilka różnych rozmiarów typów numerycznych,
największy z nich zapewnia duży zakres wartości, ale zajmuje dużo miejsca w pamięci. Dla przykładu, język C posiada typ short (dla relatywnie małych liczb), long (dla dużych liczb) oraz int (który powinien być pośrodku, ale zwykle jest identyczny z jednym z short lub long). Ten rodzaj wyboru typów miał sens w czasach, gdy rozdział pomiędzy pamięcią i dostępnymi funkcjami był szczególnie widoczny. Projektanci PHP
podjęli dobrą decyzję o uproszczeniu typów i pozostawieniu tylko dwóch typów numerycznych, odpowiadających największemu typowi całkowitemu oraz zmiennoprzecinkowemu w C.
Integer Integer to najprostszy typ; odpowiada on prostym liczbom całkowitym zarówno, dodatnim, jak i ujemnym. Dane tego typu można przypisywać do zmiennych lub używać w wyrażeniach. $int_var = 12345; $inny_int = -12345 + 12345; // równe zero
Formaty zapisu Zmienne numeryczne mogą być zapisywane w trzech postaciach: dziesiętnej, oktalnej
i szesnastkowej. Format dziesiętny jest formatem domyślnym, liczby oktalne oznaczane są przez dodanie początkowego 'O', a liczby szesnastkowe rozpoczynają się od 'Ox'. Każdy z tych formatów może być poprzedzony znakiem '-' w celu uzyskania liczby ujemnej. Na przykład: $integer_10 = 1000;
Format wpływa tylko na to, w jaki sposób liczba zostanie skonwertowana w trakcie odczytu, wartość zapisana w zmiennej $integer_8 nie pamięta, że była liczbą ósemkową. Wewnętrznie liczby te są zapisywane w postaci binarnej, ale widzimy je skonwertowane do postaci dziesiętnej, ponieważ takie jest domyślne ustawienie dla konwertowania liczb całkowitych na ciągi.
Rozmiar Jak duże (lub małe) mogą być liczby typu integer? Ponieważ typ ten odpowiada typowi long w C, który zależy od długości słowa maszyny, odpowiedź na to pytanie jest trudna. Dla typowych maszyn największa liczba całkowita to 2 31 - l (lub 2 147 483 647), najmniejsza to -(231 - 1) (lub -2 147 483 647). W PHP nie ma stałej (jak MAXINT w C) określającej największą liczbę typu integer. Na końcu tego rozdziału zamieściliśmy program określający tę liczbę. Jeżeli potrzebujesz naprawdę dużych liczb, PHP ma kilka funkcji o dowolnej dokładności (opisane w części BC rozdziału 10.).
Double Typ double to liczby zmiennoprzecinkowe, takie jak: Sfirst_double = 123.456;
$second_double = 0.456;
Seven_double = 2.0;
Zauważ, zmienna $even_double jest liczbą „okrągłą", nie znaczy to jednak, że całkowitą. Liczby integer i double zapisywane sąw różnych postaciach binarnych. Wynik wyrażenia $five = $even_double + 3;
jest liczbą double, a nie integer. W prawie wszystkich sytuacjach będziesz mógł
mieszać w wyrażeniach matematycznych dowolnie liczby double oraz integer i pozwalać PHP na konwersję typów. Domyślnie liczby double są drukowane z minimalną możliwą liczbą cyfr po przecinku; na przykład:
Smany = 2.2888800; $many_2 = 2.2111200;
$few = $many + $many_2;
p r i n t ( " $ m a n y + $many_2 = $ f e w < B R > " ) ;
da w wyniku: 2 . 2 8 8 8 8 + 2.21112 = 4 . 5
Rozdział 6.
» Typy w PHP_________________________________________95^
Jeżeli potrzebujesz precyzyjnego sterowania drukowaniem, zapoznaj się z funkcją printf opisaną w rozdziale 9.
Formaty zapisu Typowym formatem zapisu liczb double jest -x. Y, gdzie - określa liczbę ujemną, natomiast x i Y są sekwencjami cyfr pomiędzy O a 9. Część x lub część Y może zostać
opuszczona. Początkowe i końcowe zera nie mają znaczenia. Wszystkie poniższe przykłady są prawidłowymi liczbami double: $sraall_positive = 0.12345; $small_negative = -.12345; $even_double = 2.000000;
$still_double = 2.;
Można dodatkowo używać notacji naukowej, dodając literę e i żądaną potęgę liczby 10 na końcu przedstawionego przed chwilą formatu. Na przykład 2.2e-3 oznacza 2 . 2 * 1 0 - 3 . Zmiennoprzecinkowa część tego formatu nie musi być ograniczana do liczb z zakresu 1,0 i 10,0. Wszystkie poniższe przykłady są prawidłowe: $small_positive = 5.5e-3;
Zauważ, że zmienna nie pamięta, czy była podana jako liczba w notacji naukowej. W czasie drukowania liczb PHP podejmuje decyzję, czy użyć formatu naukowego do wyświetlania dużych liczb, ale nie ma to związku z oryginalnym formatem zapisu tej liczby.
Boolean Typ boolean posiada tylko wartości: prawda i fałsz, które są używane do tworzenia struktur sterujących, takich jak wyrażenia „testujące" w instrukcji if. W następnym rozdziale opiszemy, w jaki sposób można za pomocą operatorów łączyć wartości logiczne w bardziej skomplikowane wyrażenia.
Prawdziwy typ boolean jest nowością w PHP 4. PHP 3 nie miał osobnego typu boolean, a zamiast tego traktował określone wartości innych typów jako TRUE lub FALSE (podejście takie jest znane hakerom Perl). Różnica ta nie jest wielka, ponieważ nadal
możesz używać innych typów w kontekście logicznym, a PHP 4 wykonuje automatyczną konwersję typów (na końcu rozdziału wypisaliśmy kilka przypadków, kiedy zachowanie PHP 3 i PHP 4 może się różnić).
96__________________________________________Część l
»
Podstawy PHP
Stałe boolean PHP posiada parę stałych logicznych: TRUE i FALSE, które można używać w sposób następujący: if (TRUE)
print("To będzie zawsze wydrukowane ") ; else print("To nie będzie nigdy wydrukowanę ");
Interpretowanie innych typów jako boolean Można określić „prawdziwość" dowolnej wartości, która nie jest typem boolean według następujących zasad: 1. Jeżeli jest to liczba, zero odpowiada FALSE, każda inna wartość TRUE. 2. Jeżeli jest to ciąg znaków, pusty ciąg odpowiada FALSE, w przeciwnym wypadku TRUE. 3. Wartość typu złożonego (tablica lub obiekt) jest FALSE, jeżeli nie zawiera wartości, w przeciwnym wypadku — TRUE.
Przykłady Każda z poniższych zmiennych, użyta jako wyrażenie logiczne, posiada wartość logiczną określoną przez ich nazwę. $true_num = 3 + 0.14159;
$true_str = "Zmęciony i prawdziwy"; $true_array[49) = "Element tablicy"; // opis w następnej części $false_num = 999 - 999; $false_str = ""; // ciąg o długości O
Nie używaj liczb double jako warunków logicznych Mimo, że zasada 1. mówi, że liczba double 0,0 jest konwertowana do wartości boolean — false, z powodów możliwych błędów zaokrągleń niebezpiecznie jest używać liczb double jako wyrażeń logicznych. Na przykład: $floatbool = sqrt(2.0) * sqrt(2.0) - 2.0;
if ($floatbool) print("Zmiennoprzecinkowe wyrażenia boolean są niebezpieczne! "); else print("Działa ... tym razem. ") ; print ("Wartość aktualna to $floatbool ");
Zmiennej $floatbool przypisany jest wynik odejmowania iloczynu pierwiastków z dwóch od liczby dwa. Wynik powinien być równy zero, co oznacza, że $f loatbool
ma wartość logiczną false. Zamiast tego przeglądarka pokaże: Zmiennoprzecinkowe wyrażenia boolean są niebezpieczne! Wartość aktualna to 4.4408920985006E-16
Rozdział 6.
»
Typy w PHP_________________________________________97
Wartość $floatbool jest bardzo bliska 0,0, jednak nie jest to dokładnie zero i dlatego jego wartością logicznąjest true. Liczby integer są o wiele bezpieczniejsze jako wartości boolean; tak długo, jak wynik działania jest liczbą całkowitą, nie trzeba obawiać się błędów zaokrągleń.
Typ boolean w PHP 3 i PHP 4 Ponieważ PHP 3 nie ma niezależnego typu boolean, prawdziwe wartości stałych TRUE i FALSE są innych typów. Pamiętaj, że używanie tych stałych w innym kontekście niż w wyrażeniach logicznych prowadzi do niekompatybilności z PHP 4. Dobrą zasadą nieporównywanie wartości do stałej logicznej za pomocą operatora =, lecz użycie samej wartości zmiennej jako warunku logicznego. Dla przykładu załóżmy, że wynik twojej funkcji przypisany jest do zmiennej $truth_value. Zmienna ta może być liczbą lub ciągiem, ale zawsze ma może być skonwertowana do zmiennej logicznej według zasad opisanych wcześniej. Jaki jest prawidłowy sposób użycia tej zmiennej? Prawidłowym sposobem, który będzie działał zarówno w PHP 3, jak i PHP 4 jest: if (Struth_value)
// dobry styl PHP! Bezpieczny w PHP 3 i PHP 4
print("Wartością truth_value jest TRUE ");
Nieprawidłowy sposób użycia: if ($truth_value == TRUE) // niedobry styl PHP! Porównanie z boolean
print("Wartością truth_value jest TRUE ");
Zachowanie się PHP 3 i PHP 4 może być różne. Jeżeli $truth_value będzie równe np. 3, PHP 4 skonwertuje jądo wartości logicznej TRUE przed porównaniem, natomiast PHP 3 porówna 3 z aktualną wartością stałej TRUE i test da prawdopodobnie wartość FALSE.
String string służy do zapamiętania sekwencji znaków: $string_l = "Ciąg znaków w cudzysłowach."; $string_2 = 'Nieco dłuższy ciąg znaków w apostrofach'; $string_39 = " Ciąg ma trzydzieści dziewięć znaków. "; Sstring_0 = ""; // Ciąg pusty
Ciągi mogą być zamykane apostrofami lub cudzysłowami, które mają działają inaczej w programie. Ciągi z apostrofami są traktowane nieomal dosłownie, natomiast w ciągach z cudzysłowami nazwy zmiennych są zamieniane na ich wartości i interpretowane są sekwencje sterujące.
Ciągi w apostrofach Oprócz pary znaków specjalnych, ciągi w apostrofach są odczytywane i przechowywane dosłownie. Poniższy przykład: Sdoslownie = 'Ta Szmienna nie zostanie wydrukowana!\n'; print(Sdoslownie);
98__________________________________________Część l » Podstawy PHP
da w przeglądarce następujący wynik: Ta $zmienna nie zostanie wydrukowana!\n
Ciągi w apostrofach działają zgodnie z ogólną zasadą, że apostrofy innego typu nie podzielą otaczanego tekstu. To jest prawidłowy zapis: $apostrofy = 'Ten znak " nie jest problemem';
Aby wbudować w ciąg pojedynczy apostrof, należy poprzedzić go znakiem \: Sapostrofy = 'Ten apostrof \' również nie stanowi problemu';
Mimo że w większości przypadków backslash jest interpretowany dosłownie w ciągach zamkniętych apostrofami, możesz użyć dwóch takich znaków (\\) jako sekwencji sterującej dającej pojedynczy backslash. Jest to użyteczne w przypadku, gdy chcemy ten znak umieścić na końcu ciągu. $win_path = 'c: \\InetPub\\PHP\V ; print("Ścieżka w stylu Windows: $win_path ");
Przykład ten da w wyniku: Ścieżka w stylu Windows: c:\InetPub\PHP\
Mogliśmy użyć pojedynczych znaków backslash w dwóch pierwszych wystąpieniach, ale musieliśmy użyć sekwencji \\ w ostatnim wystąpieniu, aby nie została zinterpretowana sekwencja Y.
Te dwie sekwencje sterujące sąjedynym wyjątkiem od dosłownego traktowania ciągów w apostrofach.
Ciągi w cudzysłowach Ciągi otaczane znakami cudzysłowu (jak w "tym" przypadku) są przez PHP przetwarzane według dwóch zasad: 1. Odpowiednie sekwencje sterujące rozpoczynające się znakiem \ są zamieniane na znaki specjalne. 2. Nazwy zmiennych są zastępowane przez ich wartość, zamienioną na ciąg znaków. Sekwencjami sterującymi są: \n zamieniane na znak nowej linii; \r zamieniane na znak powrotu karetki (CR); \t zamieniane na znak tabulacji; \$ zamieniane na znak dolara (S); \" zamieniane na cudzysłów ("); \ \ zamieniane na \.
Rozdział 6.
»
Typy w PHP_________________________________________99_
Pierwsze trzy znaki umożliwiają wprowadzenie odstępów do ciągów. Sekwencja \$ pozwala na wstawienie do ciągu znaku $, gdy nie chcemy, aby był interpretowany jako
początek zmiennej. Sekwencja \" pozwala na wstawienie do ciągu cudzysłowu bez zakończenia go. Ostatnia sekwencja sterująca pozwala na wstawienie do ciągu znaku \, który rozpoczyna wszystkie sekwencje sterujące. Podobnie jak dla ciągów w apostrofach, terminator innego typu może być bezpiecznie wstawiany do ciągu bez sekwencji sterującej: $ma_apostrof = "Nie ma problemu 'z* apostrofami";
Interpretacja zmiennych Gdziekolwiek wystąpi w ciągu znak $, PHP stara się określić, jaka zmienna znajduje się
za znakiem $ i wstawić w to miejsce wartość zmiennej. W zależności od tego, jak jest ustawiona zmienna, może się to odbywać na kilka sposobów: * Jeżeli do zmiennej jest przypisany ciąg znaków, jest ona wstawiana (lub wklejana) do ciągu w cudzysłowach. * Jeżeli zmienna zawiera wartość inną niż ciąg znaków, wartość ta jest konwertowana do postaci wklejanego ciągu. ** Jeżeli zmienna nie posiada wartości, jest zamieniana na pusty ciąg (PHP wkleja pusty ciąg).
Prześledźmy, co dokładnie robi PHP, analizując ciąg w instrukcji print. Zauważ, że w ciągu tym znajdują się cztery znaki $, które są interpretowane jako początek nazwy zmiennej. Nazwy zmiennych kończą się pierwszym znakiem, który nie może wystąpić
w nazwie zmiennej. Dopuszczalnymi znakami są litery, cyfry i podkreślenie. Znaki kończące nazwy zmiennych w ciągu z przykładu to kolejne dwa przecinki, znak plus i lewy nawias trójkątny (<). Pierwsze dwie zmienne mają przypisane ciągi (to i tamto), więc są wklejone dosłownie. Następna zmienna ($nie_ustawiona) nie była wcześniej przypisana, więc nie jest brana pod uwagę przy tworzeniu ciągu. I ostatnia zmienna ($cos_innego), rozpoznana jako liczba zmiennoprzecinkowa. Jej wartość jest skonwertowana do ciągu (2 .2) i ciąg ten jest wklejany do ciągu wynikowego. Więcej informacji o konwertowaniu liczb do ciągów znajduje się w części „Przypisania i konwersje", poniżej.
100_________________________________________Część l »
Podstawy PHP
Jak wcześniej wspomnieliśmy, interpretacja ciągów zachodzi w momencie ich odczytywania, a nie w momencie drukowania. Jeżeli zapiszemy przykładowy ciąg w zmiennej i wydrukujemy go później, to będzie on odzwierciedlał wartości zmiennych z momentu przypisania, nawet jeżeli będą zmodyfikowane.
Znaki końca wiersza w ciągach Mimo że PHP posiada sekwencję sterującą (\n) zamienianą na znak końca wiersza, dobrze jest wiedzieć, że identycznie traktuje złamanie wiersza w ciągu. Jest to wygodne, gdy tworzymy ciąg HTML, ponieważ przeglądarka ignoruje znaki końca wiersza, możemy więc formatować nasz ciąg za pomocą znaków końca wiersza. print ("Ta strona HTML jest zbyt duża aby zmieścić się w pojedynczej linii, jednak nie oznacza to,
że potrzebujemy wielu instrukcji print !" );
Utworzyliśmy tę instrukcję w edytorze, naciskając Enter na końcu dwóch pierwszych
wierszy. Znaki nowego wiersza zostały wstawione do ciągu, więc pojedyncza instrukcja print utworzy trzy osobne wiersze. Przeglądarka zignoruje je, decydując, kiedy i czy należy złamać wiersz.
Ograniczenia Nie ma sztucznych ograniczeń długości ciągu. W granicach dostępnej pamięci możesz tworzyć ciągi dowolnej długości.
Tablice Typ tablicowy pozwala na grupowanie różnych wartości i dostępu do nich dzięki wartości indeksu (również dzięki nazwie, ale o tym później). Jeżeli zdarzyło ci się korzystać ze zmiennych Szmiennal, $zmienna2, $zmienna3 itd., możesz używać w ich miejsce tablicy ($zmienna [1], $ z m i e n n a [ 2 ] , $ z m i e n n a [ 3 ] , ...). Do elementów tablicy
można się odwoływać dzięki indeksowi w nawiasach kwadratowych ( [ 1 ] , [ 2 ] , [3]
itd.). Do tablicy PHP można przypisywać wartości różnych typów.
Poniżej zamieściliśmy kilka przykładów, które sprawdzają wartości elementów tablicy przed i po przypisaniu: print{"tabl ma wartość $tabl ");
print("tabl[0] ma wartość Stabl[0] "); print("tabl[5] ma wartość Stabl[5] "); $tabl[5] = "Element #6"; print("tabl ma wartość $tabl "); print("tabl[0] ma wartość Stabl[0] ");
print("tabl[5] ma wartość Stabl[5] ");
Wynik wykonania tego fragmentu: tabl ma wartość
tabl[0] ma wartość
tabl[5] ma wartość
Rozdział 6.
» Typy w PHP______________________________________101 tabl ma wartość Array tabl[0] ma wartość tabl [5] ma wartość Element (t6
Przed pierwszym przypisaniem PHP nie wiedział, że zmienna $ tab l jest przeznaczona na tablicę; była to po prostu niezainicjowana zmienna. Została wydrukowana jako pusty ciąg. Również odwołanie do zerowego i piątego elementu jest traktowane identycznie jak niezainicjowana zmienna. Wynik działania pierwszych trzech instrukcji print kończy się więc na wyrazie wartość.
Po wykonaniu przypisania zmienna $tabl jest teraz oficjalną tablicą, w wyniku umieszczenia jej nazwy w ciągu zwrócony zostanie predefiniowany ciąg Array. Element tablicy o indeksie 5 zawiera ciąg Element # 6 (jak w większości języków, elementy tablicy są numerowane od 0) i mamy do niego dostęp poprzez podanie tego indeksu. To jest jedyna zmiana, element zerowy pozostaje nadal niezainicjowana zmienną.
Implementacja tablic Tablice są jedną z najbardziej użytecznych funkcji w PHP i mimo że wyglądają tak samo jak tablice w innych językach, są implementowane w zupełnie inny sposób. W większości języków programowania deklaruje się tablice za pomocą wyrażenia podobnego do: mt int_array[10] ;
//to NIE jest PHP
Deklaracja taka rezerwuje blok pamięci na 10 liczb całkowitych, do których można odwoływać się poprzez indeksy od O do 9.
W PHP tablice są asocjacyjne; gdy przypisujesz wartość do elementu tablicy, dodajesz jednocześnie do tablicy miejsce na element związany z indeksem, za pomocą którego można się odwołać do tej wartości (jest to mechanizm podobny do tablic mieszających — tablice w PHP to raczej tablice mieszające, a nie klasyczne). Jedną z konsekwencji tego mechanizmu jest to, że nie musisz się obawiać przypisywa-
nia wartości do elementów tablicy o bardzo dużych indeksach: Stablica[100000000] = "Nie obawiaj się";
// to jest OK
Wykonanie tej linii nie zarezerwuje 100 milionów elementów. Elementy o niższych indeksach prawdopodobnie jeszcze nie istnieją, więc nie zajmuj ą pamięci.
Ciągi znaków jako indeksy tablicy Do tej pory używaliśmy liczb całkowitych jako indeksów. Możemy również korzystać z ciągów znaków, np.: $smakolyk["Hiszpański"] = "paella"; $smakolyk["Japoński"] - "sashimi"; Ssmakolyk["Szkocki"] = "haggis?";
102_________________________________________Część
l
«
Podstawy
PHP
Takich indeksów używa się identycznie jak indeksów numerycznych. Indeksy numeryczne i ciągi znaków mogą być bez obaw mieszane w tej samej tablicy.
Czy w PHP są struktury? Niektóre języki programowania (C, Pascal) pozwalają na używanie „struktur" bądź „rekordów", które umożliwiają łączenie ze sobą zmiennych różnych typów. W tych językach programowania podstawowa zasada wyboru typu złożonego brzmi: jeżeli wartości są tych samych typów, używani tablicy, w przeciwnym przypadku używam struktury. PHP ma typ obiektowy, który może posłużyć jako rekord lub struktura. Nawet przed wprowadzeniem typu obiektowego PHP nie będzie potrzebował struktur, ponieważ tablice nie są ograniczone do przechowywania elementów jednego typu. Jeżeli przenosisz
program z innego języka do PHP i masz w kodzie struktury, możesz użyć tablic indeksowanych ciągami odpowiadającymi nazwom pól struktury.
Inne własności tablic W tym rozdziale przedstawiliśmy jedynie podstawowe własności tablic. Tablice dodatkowo mogą być wielowymiarowe, ich wartości mogą być przypisywane różnymi metodami. Istnieje wiele funkcji związanych z tablicami pozwalających na łatwe sprawdzanie za-
wartości tablic i manipulowanie nimi. Wrócimy do tego w rozdziale 11.
Obiekty Ostatnim z pięciu typów PHP jest typ obiektowy, wprowadzający PHP do modnego świata programowania obiektowego (OOP). W rozdziale tym podamy tylko krótkie wprowadzenie do koncepcji i składni programowania obiektowego w PHP, pełny opis znajdziesz w rozdziale 33.
Przegląd OOP Używając podejścia obiektowego programista definiuje nowe jednostki zwane klasami. Każda klasa jest nowym typem danych. Po zdefiniowaniu klasy można utworzyć do-
wolną liczbę obiektów będącymi egzemplarzami bądź instancjami klasy.
Proces jest podobny do definiowania struktur lub rekordów w językach C lub Pascal. Programowanie obiektowe idzie jednak dalej, dołączając jedną lub więcej z następujących własności:
* Metody: oprócz pól danych obiekty mogą posiadać metody (funkcje definiowane na rzecz konkretnej klasy).
Rozdział 6.
»
Typy w PHP_________________________________________103
* Dziedziczenie: klasa może dziedziczyć po innej klasie, co spowoduje, że będzie mieć wszystkie pola i metody z klasy będącej jej przodkiem. Odziedziczone atrybuty mogą być rozszerzane (poprzez dodanie nowych pól danych i metod) lub przesłaniane (przez ponowną definicję odziedziczonego atrybutu). * Hermetyzacja: definicja klasy może określać, które atrybuty będą dostępne dla kodu nie będącego kodem klasy. * Polimorfizm: zachowanie metody może różnić się w zależności od liczby i typu argumentów wywołania.
Jak bardzo obiektowy jest PHP? PHP posiada ograniczoną implementację programowania obiektowego. Pozwala na definicję klas i metod oraz dziedziczenie, jednak nie zezwala na dziedziczenie wielobazowe oraz prawdziwą hermetyzację, a w ograniczonym zakresie pozwala na polimorfizm. Chociaż programiści znający C++, Java, Smalltalk lub Common Lisp będą tęsknić za subtelnościami i zaawansowanymi możliwościami tych systemów, jednakże system obiektów PHP jest niezmiernie użyteczny.
Definiowanie klas w PHP Wydruk 6.1 zawiera przykładową definicję klasy w PHP. Klasa tworzy stos, z metodami push ( ) (położenie elementu na stos) i pop ( ) (usunięcie elementu ze stosu). Dodatkowo stos przechowuje tylko liczby całkowite i nie pozwala na wstawienie elementu innego typu. Oprócz konstrukcji obiektowych przykład ten używa kilku własności PHP, które nie były jeszcze omawiane. Jeżeli czegoś nie rozumiesz, opuść tę część i wróć po przeczytaniu rozdziału 30. Wydruk 6.1. Definicja prostej klasy w PHP___________________________________ class Intstack ( /* Stos ograniczony do liczb całkowitych */ var $the_stack;
var Scount = 0;
function push ($intvar) {
if (is_integer($intvar})
<
$this->the_stack[$this->count] = $intvar; // wstawienie do stosu $this->count++;
}
// zwiększenie licznika
print! "Wstawienie Sintvar udane. ");
else
}
print! "Intstack przyjmuje tylko liczby całkowite! ");
104_________________________________________Część l « Podstawy PHP function pop() (
Klasa intstack ma dwie zmienne ($the_stack i $count) oraz dwie metody (push ( ) i pop ( ) ) . Zmienne zostały zadeklarowane za pomocą słowa kluczowego var, a definicja metod jest podobna do definicji zwykłej funkcji, oprócz tego, że znajdują się w ciele klasy. Metody mogą odwoływać się do zmiennych klasy dzięki specjalnej zmiennej $this, która wskazuje na obiekt.
Tworzenie obiektów Po zdefiniowaniu klasy można tworzyć obiekty za pomocą słowa kluczowego new poprzedzającego nazwę klasy. Metody wywołujemy używając operatora -> na wynikowym obiekcie. Poniżej przykład użycia klasy Intstack zdefiniowanej na wydruku 6.1. $my_stack = new Intstack;
$my_stack->push(l J ; $my_stack->push(49) ; $my_stack->push("To nie podziała"); $pop_result = $my_stack->pop() ; print("Na górze stosu było $pop_result ");
Spop_result = $my_stack->pop();
print("Na górze stosu było $pop_result "); $pop_result = $my_stack->pop();
Wynikiem tego fragmentu kodu jest: Wstawienie l udane. Wstawienie 49 udane.
Intstack przyjmuje tylko liczby całkowite! Na górze stosu było 49 Na górze stosu było l Stos jest pusty!
Kontrola typów Ponieważ zmienne mogą zmieniać typy po przypisaniach, czasami niezbędne jest sprawdzenie typu zmiennej w czasie działania programu. PHP posiada zarówno ogólną
funkcję kontrolującą typ (gettype ( ) ) , jak i indywidualne funkcje logiczne dla każdego z pięciu typów. Funkcje te wraz z ich alternatywnymi nazwami są zebrane w tabeli 6.1.
Rozdział
6.
»
Typy
w
PHP_________________________________________105
Tabela 6.1.
Funkcje kontroli typów Funkcja
Działanie
gettype ( a r g )
Zwraca ciąg określający typ argumentu: integer, double, string, array, object lub unknown type
is_int (arg)
is_integer(arg) is_long(arg)
is_double ( a r g ) is_float(arg)
Zwraca true, jeżeli arg jest liczbą całkowitą, false, jeżeli nie jest
Zwraca true, jeżeli arg jest liczbą zmiennoprzecinkową, false, jeżeli nie jest
is_real(arg)
is_bool ( a r g )
Zwraca true, jeżeli arg jest wartością logiczną (TRUE lub FALSE), false, jeżeli nie jest
is_string ( a r g )
Zwraca true, jeżeli arg jest ciągiem znaków, f a l s e , jeżeli nie jest
is_array ( a r g )
Zwraca true, jeżeli arg jest tablicą, false, jeżeli nie jest
is_object (arg)
Zwraca true, jeżeli arg jest obiektem, false, jeżeli nie jest
Przypisania i konwersje PHP często konwertuje wartości z jednego typu na inny, wymagany w bieżącym zastosowaniu. Programista może również zażądać niektórych z takich konwersji.
Działanie konwersji typów Zasady konwersji w PHP są wyliczone poniżej (nie ma tu obiektów, ponieważ ich konwersje są mało użyteczne).
* Integer na double: tworzona jest liczba zmiennoprzecinkową odpowiadająca całkowitej (na przykład 4 jest zamieniane na 4 . 0).
* Double na integer: odrzucana jest część ułamkowa, liczbę zaokrągla się w stronę zera. * Liczba na boolean: FALSE, jeżeli liczba jest dokładnie równa O, w przeciwnym wypadku TRUE.
* Liczba na string: tworzony jest ciąg wyglądający dokładnie jak wydrukowana liczba. Liczby całkowite są drukowane jako sekwencja cyfr, liczby zmiennoprzecinkowe przedstawiane są z minimalną możliwą precyzją. Bardzo duże liczby zmiennoprzecinkowe są zamieniane na zapis naukowy.
* Boolean na liczbę: TRUE na l, FALSE na 0. * Boolean na ciąg: TRUE na'!', FALSE na 'O'.
106_________________________________________Część
l
»
Podstawy
PHP
** String na liczbę: odpowiednik „czytania" liczby z ciągu znaków, następnie kon-
wersja do odpowiedniego typu. Jeżeli liczba nie daje się przeczytać, wartość wynosi zero.
* String na boolean: FALSE, gdy ciąg jest pusty lub ciąg 'O', TRUE w innych przypadkach. * Typy proste na tablicę: odpowiednik utworzenia tablicy i przypisania wartości typu prostego do komórki o indeksie zero. * Tablica na liczbę: liczba l, gdy tablica zawiera wartości, w przeciwnym wypadku 0.
** Tablica na boolean: FALSE, jeżeli tablica jest pusta, w przeciwnym przypadku TRUE.
* Tablica na string: 'Array'.
Jawne konwersje PHP zezwala na trzy sposoby manipulacji typami: funkcje konwersji, rzutowanie typów (jak w języku C) oraz wywołanie settype ( ) na zmiennej: 1. Funkcje intval (), doubleval () i strval () konwertują wartość argumentu
na odpowiednio liczbę integer lub double, albo ciąg znaków (do chwili napisania książki nie było funkcji boolval). 2. Każde wyrażenie może być poprzedzone rzutowaniem typu (nazwa typu w nawiasach), co konwertuje wynik wyrażenia do żądanego typu. 3. Jako pierwszy argument funkcji settype ( ) może wystąpić dowolna zmienna, która zostanie zmieniona na typ podany w drugim argumencie funkcji. Każdy z poniższych przykładów umieszcza prawidłową liczbę dalmatyńczyków (l01) w zmiennej $dog_count:
Żaden z przykładów nie konwertuje w sposób bezpośredni, niepotrzebnie konwertując typ double na ciąg. Wystarczy od razu skonwertować s t r i n g na i n t e g e r .
Rozdział 6. » Typy w PHP_________________________________________107
Każdej z sześciu nazw typów (integer, double, boolean, string, array i object) można użyć przy rzutowaniu typów oraz jako drugi argument funkcji s e t t y p e f ) . Dodatkowo przy rzutowaniu (ale nie w funkcji settype ()) dopuszcza się kilka nazw zastępczych: ( i n t ) zamiast ( i n t e g e r ) , ( f l o a t ) zamiast (double) oraz (bool) zamiast ( b o o l e a n ) .
Przykłady konwersji Na wydruku 6.2 podany jest kod, który wyświetla kilka konwersji typów w tabeli HTML, pokazanej na rysunku 6.1 (kod ten nie jest przykładem stylu programowania i używa kilku nieopisanych jeszcze konstrukcji). Wydruk 6.2. Konwersje typów______________________________________________ Stype_examples[0] = 123; // liczba całkowita
$type_examples[1] = 3.14159; // liczba zmiennoprzecinkowa $type_examples[2] = "ciąg bez liczb";
108_________________________________________Część l » Podstawy PHP
Inne użyteczne konwersje typów Funkcje wymienione w tabeli 6.2 nie są funkcjami konwersji typów, ale zwracają wartość innego typu niż typ głównego argumentu. Tabela 6.2.
Inne funkcje konwersji typów
Z typu \ na typ
Integer
String
Array
ord()
Integer Double
c e i l O , f loor ( ) , round ( }
String
chr ()
explode ( ) implode ( )
Array
Funkcja ceil () jako argument pobiera liczbę double i zwraca liczbę typu integer, która jest od niej większa lub jej równa. Na przykład: $my_double = 4.7;
Funkcja round ( ) zwraca liczbę całkowitą najbliższą liczbie double podanej jako argument. Jeżeli część ułamkowa jest równa dokładnie 0,5, liczba jest zaokrąglana w stronę liczby parzystej. $my_int = round(4.7); // $my_int = 5 $my_int = round(-4.7); // $my__int = -5 $my_int = round(-4.5); // ?my_int = -4
Zauważ, że nie ma funkcji truncate ( ) (odrzucenie części ułamkowej), ponieważ konwersja double na integer daje taki właśnie wynik.
Funkcja chr ( ) pobiera integer i zwraca ciąg składający się z jednej litery o kodzie
ASCII równym podanemu argumentowi. Funkcja ord ( ) działa odwrotnie, zwraca wartość ASCII pierwszego znaku ciągu. Funkcje implode ( ) i explode ( ) pozwalają na konwersję pomiędzy ciągiem i tablicą. implode ( ) tworzy ciąg z elementów tablicy podanej jako drugi argument, oddzielając elementy tablicy ciągiem podanym jako pierwszy argument. Na przykład: $slowa[0] = "Jedno"; $slowa[l] = "krótkie";
» Typy w PHP______________________________________109
da w efekcie Jedno krótkie zdanie.
Explode ( ) działa odwrotnie, tworząc tablicę z elementów ciągu. $slowa - explode( " ", "Jedno krótkie zdanie.");
Przepełnienie liczby całkowitej Jedną ze sprytniejszych konwersji typów wykonywanych przez PHP jest stosunkowo często występujący przypadek, gdy wystąpi przepełnienie liczby całkowitej. Zmienna
jest konwertowana wtedy na typ double, ponieważ typ ten może przechowywać liczby o wiele większe niż integer. Na przykład: $za__duzo = 111; for ($count = 0; Scount < 5; Scount++) (
$za_duzo = 1000 * $za_duzo; print (" Czy $za_duzo to jeszcze integer? ");
)
da w wyniku: Czy Czy Czy Czy Czy
111000 to jeszcze integer? 111000000 to jeszcze integer? 111000000000 to jeszcze integer? 1.11E+14 to jeszcze integer? 1.11E+17 to jeszcze integer?
Zmiana sposobu wyświetlania liczby na postać naukową, jest związana z zamianą typu zmiennej $za_duzo na typ double. Oczywiście można w ten sposób utracić część informacji, ponieważ double ma ograniczoną dokładność, ale PHP stara się zrobić wszystko, co jest możliwe, aby uniknąć błędu.
Szukamy największej liczby całkowitej Jeżeli musisz dokładnie wiedzieć, jak duże liczby całkowite obsługuje PHP, a uważasz, że nie jest to 231-1, przedstawiamy funkcję, która zwraca tą wartość. function maxint() { /* funkcja określająca wielkość typu integer funkcja zakłada, że największy integer jest w postaci 2"n-l */
$to_test = 2; while(l) ( Slast = $to_test; Sto_test = 2*Sto_test; if (($to_test < Slast) l l (!is_int($to_test))) return (Slast + (Slast -1)); )
> /* przykład użycia */ Smaxint = maxint O; print{"Naj większa liczba całkowita to $maxint ");
110_________________________________________Część
l
*
Podstawy
PHP
Podsumowanie PHP 4 posiada sześć typów: integer, double, boolean, string, array i object. Cztery z nich to typy proste: integer to liczby całkowite, double to liczby rzeczywi-
ste, boolean to wartości prawda i fałsz, natomiast string to łańcuch znaków (typ boolean jest nowością w PHP 4). Tablice stanowią typ złożony z innych wartości PHP indeksowanych za pomocą liczb lub ciągów. Obiekty są egzemplarzami klas definiowanych przez programistę, które zawierają zarówno zmienne, jak i funkcje klasy. Klasy mogą dziedziczyć funkcje i zmienne z innych klas. W PHP tylko wartości posiadają typy — zmienne nie posiadają wewnętrznego typu, innego niż typ ostatniego przypisanej wartości. PHP samoczynnie konwertuje typy, jeżeli jest to wymagane przez kontekst, w jakim została użyta wartość. Programista może również jawnie kontrolować typy zmiennych poprzez użycie konwersji lub rzutowania.
Rozdział 7.
Sterowanie W tym rozdziale: * Tworzenie i łączenie warunków logicznych * Instrukcje warunkowe if i switch + Pętle while i for
* Przerywanie przetwarzania strony za pomocą exit i die
Trudno jest napisać interesujący program, jeżeli wykonanie programu nie zależy od czynników zewnętrznych. Można stworzyć kod, którego wykonanie zależy tylko od wartości zmiennych, ale jest to równie pasjonujące, co wypełnianie formularza. Programiści chcą pisać programy, na które coś oddziałuje (świat, czas, wprowadzone dane, zawartość bazy danych), a program na skutek tego oddziaływania robi coś innego.
Takie zachowanie programu wymaga zastosowania instrukcji sterujących, które określają, jak w określonej sytuacji ma zachować się program. W poprzednim rozdziale użyliśmy konstrukcji if bez wyjaśnienia, jak ona działa, w tym rozdziale skupimy się na instrukcjach sterujących oferowanych przez PHP. Do doświadczonych programistów C: wszystkie instrukcje sterujące w PHP są najbardziej zbliżone do C, wszystkie struktury tutaj użyte działają identycznie. Możesz bezpiecznie przejść do podsumowania na końcu tego rozdziału.
Będziemy tu mówić o dwóch rodzajach instrukcji sterujących: instrukcjach warunkowych i pętlach. Instrukcja warunkowa powoduje rozdzielenie ścieżki wykonania programu. W zależności od warunku program może pójść na prawo bądź na lewo, podążając inną ścieżką aż do końca programu, lub ścieżki powtórnie się łączą. Pętla jest specjalnym rodzajem rozgałęzienia, w którym jedna ze ścieżek powraca na początek pętli, ponawiając sprawdzenie warunku i wykonanie ciała pętli.
112_________________________________________Część l
»
Podstawy PHP
Zanim wykorzystamy instrukcje sterujące, musimy umieć tworzyć odpowiednie warunki. Rozpoczniemy od bardzo prostych warunków wykorzystujących stałe TRUE i FALSE,
a następnie będziemy tworzyć coraz bardziej skomplikowane konstrukcje.
Wyrażenia logiczne Każda z instrukcji sterujących opisanych w tym rozdziale posiada dwie oddzielne części: warunek (określający, która część struktury będzie wykonana) oraz sam kod (osobne
gałęzie kodu lub ciało pętli). Wyrażenia logiczne działają poprzez wyliczenie wartości
wyrażenia, którego wartość jest traktowana jako prawda lub fałsz.
Stałe logiczne Najprostszym rodzajem wyrażenia jest po prostu wartość. Najprostszymi wartościami logicznymi są stałe TRUE i FALSE. Możemy np. wstawić je do warunku instrukcji if-else: if (TRUE)
print{"To będzie zawsze wydrukowane ") ; else print("To nie będzie nigdy wydrukowane ");
lub zamiennie: if (FALSE)
printC'To nie będzie nigdy wydrukowane ") ; else printC'To będzie zawsze wydrukowane ") ;
Operatory logiczne Operatory logiczne wiążą wartości logiczne i dają w wyniku nowe wartości logiczne.
Standardowe operatory logiczne (and, or, not i exclusive or) są dostępne w PHP.
Tabela 7.1. Operatory logiczne Operator and
°
r
! xor
&s
ll
Działanie
Daje wartość TRUE, gdy oba argumenty są TRUE
Daje wartość TRUE, gdy jeden z argumentów (lub oba) jest TRUE TRUE, gdy jego argument jest FALSE, FALSE gdy argument jest TRUE TRUE, gdy jeden z argumentów (ale nie oba) jest TRUE To samo co 'and', ale ściślej wiąże argumenty (patrz opis kolejności wykonywania w dalszej części rozdziału) To samo co 'or', ale ściślej wiąże argumenty
Operatory & & i I I są znane programistom C. Operator '!' jest czasami zwany operatorem not. Dla przykładu rozważmy następujące wyrażenie: (($instrukcja_l && Sinstrukcja_2) l ! ($instrukcja_l ii !$instrukcja_2) l l (!$instrukcja_l SS $instrukcja_2) l l (!Sinstrukcja_l ss !$instrukcja_2))
Wyrażenie to jest tautologią, co oznacza wyrażenie zawsze prawdziwe niezależnie od wartości zmiennych „instrukcja". Dla dwóch zmiennych istnieją cztery kombinacje wartości logicznych, każda reprezentowana przez jedno wyrażenie z operatorem & & . Jedno z nich musi być prawdziwe, a ponieważ są one połączone operatorem l i , całe wyrażenie jest prawdziwe. Tutaj mamy przykład innej tautologii z użyciem operatora xor: ((3instrukcja_l and $instrukcja_2 and $instrukcja3) xor ((!($instrukcja_l and $instrukcja_2)) or (!(Sinstrukcja_l and $instrukcja_3)) or (!($instrukcja_2 and $instrukcja_3))))
Tłumacząc na polski: „Z podanych trzech wyrażeń jedno spełnia tylko jedno z podanych dwóch twierdzeń — 1) wszystkie trzy wyrażenia są prawdziwe, 2) istnieje para wyrażeń, z których oba nie są prawdziwe".
Kolejność operatorów logicznych Niektóre operatory logiczne mają wyższy priorytet od innych, jednak kolejność może być zawsze zmieniona przez użycie nawiasów. Operatory logiczne wymienione w malejącym porządku priorytetów to: !, &&, I I , and, xor, or. Operatory and, xor i or mają o wiele niższy priorytet, operator ' =' ma od nich priorytet wyższy (ale nie od & &). Kompletna tabela kolejności operatorów znajduje się w podręczniku dostępnym pod adresem http://tvvvw.php.net.
Skracanie operatorów logicznych Jedną z bardzo użytecznych własności operatorów logicznych jest to, że łączą się od lewej do prawej oraz automatycznie się skracają, co oznacza, że nie jest obliczana wartość drugiego argumentu, jeżeli jego wartość jest nieważna po obliczeniu wartości argumentu pierwszego. Chcesz np. znać orientacyjną wartość podzielenia jednej liczby przez drugą, ale chcesz równocześnie uniknąć błędu dzielenia przez zero. Możesz najpierw sprawdzić, czy podzielnik jest różny od zera, używając operatora ! = (różny): if ($podz != O ss Sliczba / $podz > 2) print! "Więcej niż dwa!");
W przypadku gdy $podz jest równy zero, operator & & powinien zwrócić FALSE bez względu na wartość drugiego wyrażenia. Ponieważ z powodu skracania nie wykona się
114_________________________________________Część l « Podstawy PHP
drugie wyrażenie, unikniemy błędu dzielenia przez zero. W przypadku gdy $podz jest różny od zera, operator & & ma zbyt mało informacji i musi obliczyć wartość logiczną drugiego wyrażenia. Do tej pory formalnie opisaliśmy stałe TRUE i FALSE i sposób ich użycia. Teraz zajmiemy się operatorami, które pozwolą na zbudowanie prawdziwych wyrażeń logicznych.
Operatory porównania W tabeli 7.2 zamieszczone są operatory porównania, które mogą być używane do porównywania zarówno liczb, jak i ciągów (przeczytaj ostrzeżenie w dopisku). Tabela 7.2.
Operatory porównania
Operator
Nazwa
Opis
— iK
Równy
Prawdziwy, jeżeli argumenty są równe, w przeciwnym przypadku fałszywy
Różny
Fałszywy, jeżeli argumenty są równe, w przeciwnym przypadku prawdziwy
<
Mniejszy
Prawdziwy, jeżeli lewy argument jest mniejszy, w przeciwnym przypadku fałszywy
>
Większy
Prawdziwy, jeżeli lewy argument jest większy, w przeciwnym przypadku fałszywy
<-
Mniejszy
Prawdziwy, jeżeli lewy argument jest mniejszy lub równy, w przeciwnym przypadku fałszywy
lub równy
>=s==
Większy
Prawdziwy, jeżeli lewy argument jest większy lub równy, w przeciwnym
lub równy
przypadku fałszywy
Identyczny
Prawdziwy, jeżeli argumenty są równe i tych samych typów, w przeciwnym przypadku fałszywy (jest to nowość w PHP 4)
Jako przykład wykonamy kilka przypisań, a następnie skonstruujemy warunek, który jest zawsze prawdziwy: Strzy = 3; Scztery = 4; Śpi = 3.14159;
if (($trzy == $trzy) and (Scztery == $cztery) and ($trzy != Scztery) and ($trzy < Scztery) and ($trzy <= Scztery) and (Scztery >- $trzy) and (Strzy <= $trzy) and (Śpi > Strzy) and
(Śpi <= Scztery)) print("Moja wiara w matematykę ocalaia! "); else print("Na pewno się nie pomyliłeś? ") ;
Rozdział 7. * Sterowanie
115
Uważaj na bardzo częsty błąd pomylenia operatora przypisania c = ' ) z operatorem porównania ( ' = = ' ) . Wyrażenie if ($trzy = Scztery) ... przypisze (niespodziewanie) wartość zmiennej Scztery do zmiennej $trzy, a poza tym wynik będzie prawdziwy, jeżeli $cztery jest różne od zera.
Kolejność operatorów Mimo że duże zaufanie do reguł kolejności może być kłopotliwe dla osoby czytającej twój kod, jednak należy zapamiętać, że operatory porównania mają wyższy priorytet niż operatory logiczne. Oznacza to, że warunek: if ($small_num > 2 && $small_num < 5) ...
nie wymaga żadnych dodatkowych nawiasów. Ostrożnie z porównaniami
Mimo że operatory porównania działają zarówno z liczbami, jak i ciągami, kryje się tutaj kilka pułapek. Po pierwsze, mimo że porównania mniejszy lub równy, większy lub równy na liczbach double (lub pomiędzy integer i double) zawsze są bezpieczne, niebezpieczne jest poleganie na równości liczb double, szczególnie jeżeli są wynikiem działań matematycznych. Problem tkwi w błędach zaokrągleń, które mogą spowodować, że liczby teoretycznie równe nieco się od siebie różnią. Po drugie, pomimo że operatory porównania działają równie dobrze na ciągach, jak i na liczbach, to automatyczna konwersja typów PHP może doprowadzić do nieintuicyjnych wyników, gdy ciągi zostaną zinterpretowane jako liczby, na przykład: $ciag_l = "00008";
Sciag_2 = "007"; $ciag_3 - "00008-OK"; if ($ciag_2 < $ciag_l) print ("$ciag_2 jest mniejszy od $ciag_l "); if ($ciag_3 < Sciag_2) print ("Sciag_3 jest mniejszy od $ciag_2 "); if ($ciag_l < $ciag_3) print ("$ciag_l jest mniejszy od Sciag_3 ");
daje w wyniku (opatrzonym komentarzem): 007 jest mniejszy od 00008 // porównanie liczb 00008-OK jest mniejszy od 007 // porównanie ciągów 00008 jest mniejszy od 00008-OK // porównanie ciągów — sprzeczność!
PHP konwertuje ciągi na liczby, jeżeli tylko potrafi to zrobić i gdy obie strony mogą być potraktowane w ten sposób (porównywane są wartości liczbowe, a nie ciągi). Projektanci PHP uważają, że nie jest to błąd, to po prostu własność. Zalecamy korzystanie z funkcji strcmp ( ) , jeżeli porównywane ciągi mają jakąkolwiek szansę być zinterpretowane jako liczby (rozdział 9.).
116_________________________________________Część l
»
Podstawy PHP
Porównywanie ciągów Operatory porównania mogą być używane do porównywania ciągów tak samo jak liczb (przeczytaj ostrzeżenie powyżej). Możemy się spodziewać, że poniższy kod wypisze skojarzone z nim zdanie: if (("Marek" < "Maria") and ("Maria" < "Margaryna")) { print("W słowniku pomiędzy Marek i Maria "); print("znajduje się Margaryna, "); }
Porównanie zależy od wielkości liter. Przykład ten wypisze zdanie tylko dlatego, że w słowie Margaryna zastosowaliśmy niewłaściwą wielkość liter. Z powodu nieodpowiedniej wielkości liter poniższy przykład nic nie wydrukuje: if (("głębokie morze" < "gramatyka") and ("gramatyka" < "Grażyna")) {
print("Pomiędzy głębokie morze a Grażyna ");
print("znajduje się gramatyka. ");
)
Operator trójskładnikowy Jedną z bardziej użytecznych konstrukcji jest trójskładnikowy operator porównania, który zajmuje miejsce pomiędzy operatorem logicznym a prawdziwą instrukcją warunkową. Jego działanie polega na użyciu wartości logicznej pierwszego wyrażenia do wyboru, które z pozostałych dwóch wyrażeń będzie wynikiem operatora. Składnia tego operatora jest następująca: wyrażenie-logiczne ? wyrażenie-prawda : w y r a ż e n i e - f a ł s z
Wynikiem tego wyrażenia jest wyrażenie-prawda, jeżeli wyrażenie-logiczne ma wartość TRUE lub wyrażenie-fałsz, w przeciwnym przypadku. Poniższe wyrażenie przypisuje np. do $max_num wartość $first_num lub $second_ num w zależności od tego, która z nich jest większa: $max_num = Sfirst^num > $second_num ? $first_num : $second_num;
Wyrażenie to zastępuj e następuj ącą konstrukcj ę: if ($first_num > Ssecond^num) $max_num = $first_num;
Instrukcje warunkowe Dwoma głównymi instrukcjami sterującymi są if i switch, if to prawdopodobnie pierwsza instrukcja warunkowa, jakiej wszyscy się uczą. Switch jest jej użyteczną odmianą w szczególnych przypadkach, gdy potrzebujesz kilku gałęzi opartych o tę samą
wartość, a seria instrukcji if byłaby niewygodna.
If-else Składnia dla instrukcji if jest następująca: if
(test) wyrażenie_l
lub z opcjonalną gałęzią else: if (test)
wyrażenie_l
else wyrażenie_2
Podczas wykonywania instrukcji if obliczana jest wartość wyrażenia test, jego wartość jest interpretowana jako wartość logiczna. Jeżeli test ma wartość TRUE, wykonywane jest wyrażenie_l, w przeciwnym przypadku wykonywane jest wyrażenie_2. Jeżeli wyrażenie test ma wartość FALSE, a nie ma części else, wykonywana jest po prostu następna instrukcja po konstrukcji if. Zauważ, że każde „wyrażenie" może być zarówno jedną instrukcją, blokiem instrukcji lub inną instrukcją warunkową (każda jest traktowana jako pojedyncza instrukcja). Instrukcje warunkowe mogą być dowolnie zagnieżdżane. Wyrażenia logiczne mogą być prawdziwymi wyrażeniami typu boolean (TRUE, FALSE lub wynik operatora logicznego, albo funkcji logicznej) lub wartościami innych typów, interpretowanymi jako wartości logiczne. _^X*
Pełny °Pis znajduje się w rozdziale 6. W skrócie przypomnimy, że liczba ( >1 cią " '°' lub Pusty c'3& "" traktowane są jako false, natomiast inne wartości traktowane są jako true.
Poniższy przykład drukujący różnicę bezwzględną pomiędzy liczbami, pokazuje zagnieżdżanie instrukcji warunkowych i interpretację wyrażeń. if ($first - Ssecond) if (Sfirst > Ssecond) { $difference = $first - $second; print("Różnica wynosi $difference. "); ) else ( Sdifference - Ssecond - $first; print("Różnica wynosi Sdifference. ");
118_________________________________________Część
l
»
Podstawy
PHP
}
else
print("Nie ma żadnej różnicy. ");
Kod ten polega na tym, że wartość O jest interpretowana jako fałsz, jeżeli różnica wynosi zero, drukowany jest komunikat o braku różnicy. Jeżeli liczby się różnią, wykonywane są następne instrukcje (przykład ten jest sztuczny, ponieważ warunek $ first ! = $second załatwiłby sprawę bardziej wszechstronnie).
Dołączamy else Programiści Pascala mogą zastanawiać się, w jaki sposób klauzula else wie, do której instrukcji if należy. Zasada jest prosta i identyczna jak w większości języków oprócz Pascala. Instrukcja else jest dołączana do najbliższej instrukcji if, respektując ograniczenia nawiasów klamrowych. Jeżeli chcesz się upewnić, że wyrażenie if pozostanie bez części else, musisz otoczyć je klamrami. if ($num % 2 == 0) // $num jest parzyste ? f if (Snum > 2) print("Liczba nie jest liczba parzysta "}; )
else
print("Liczba jest nieparzysta ");
Fragment ten wypisze „Liczba nie jest liczbą parzystą", jeżeli $num będzie parzystą liczbą większą od 2; „Liczba jest nieparzysta", jeżeli $num jest nieparzysta; nic nie wypisze, jeżeli liczba będzie wynosiła 2. Jeżeli usuniemy klamry, else zostanie przyłączone do wewnętrznej instrukcji if; program nieprawidłowo wypisze „Liczba jest nieparzysta" jeżeli liczba będzie równa 2; nic nie wypisze, jeżeli liczba będzie nieparzysta. ^^\ \^
W przykładach często używamy operatora „ % " , opisanego w rozdziale 10. Dla potrzeb tych przykładów powinieneś wiedzieć, że $x % $y jest zero, jeżeli $x dzieli się bez reszty przez $y.
Else-if Można wykonać kaskadową sekwencję testów, jak w poniższej zagnieżdżonej instrukcji if: if ($day == 5) print("Pięć złotych obraczek "); else if ($day == 4)
Do powyższego kodu zastosowaliśmy wcięcia pokazujące właściwą strukturę składni. Warto formatować w ten sposób kod, nie wszyscy się tym przejmują i rozpoczynają każdy else w pierwszej kolumnie.
Konstrukcja ta na tyle często występuje, że wprowadzono specjalną konstrukcję elseif do obsługiwania takich warunków. Przepiszmy jeszcze raz powyższy przykład: if ($day — 5) print("Pięć złotych obraczek "); elseif ($day == 4) print("Cztery śpiewające ptaki ");
Konstrukcja if, elseif, elseif, ... pozwala na wykonanie sekwencji testów i wykonanie tylko pierwszej pasującej gałęzi. Teoretycznie jest to składniowo różna instrukcja od przedstawionej w poprzednim przykładzie (mamy jedną instrukcję z pięcioma rozgałęzieniami, zamiast pięciu zagnieżdżonych instrukcji), ale działanie jest identyczne. Możesz używać tej konstrukcji, która wydaje ci się wygodniejsza w konkretnej sytuacji. Warunki i tryb HTML Jak wcześniej mówiliśmy, możesz dowolnie przełączać się pomiędzy trybem PHP i HTML. Jeżeli musisz włączyć duże fragmenty HTML, które nie posiadają dynamicznego kodu lub interpolowanych zmiennych, prościej i bardziej efektywnie jest przełączyć się do trybu HTML, zamiast umieszczać kod przy UŻyciU print lub echo.
Ale nie jest oczywiste, że strategia ta działa również wewnątrz instrukcji warunkowych. Można użyć PHP do wyboru, który fragment HTML należy wysłać, a następnie „wysłać" odpowiedni fragment dzięki chwilowemu przełączeniu się do trybu HTML.
Poniższy, niewygodny kod używa instrukcji print do stworzenia strony HTML na podstawie spodziewanej płci użytkownika (zakładamy istnienie funkcji logicznej female o , która ją sprawdza).
if (female()) t print ("Witryna tylko dla kobiet") ;
print ("") ; print("Witryna ta została utworzona tylko "); print("dla kobiet. Mężczyźni nie są tu mile widziani!"};
} else ( print("Witryna tylko dla meżczyzn "); print ( "" ) ;
print{"Witryną ta została utworzona tylko "};
120______________________________________Część l » Podstawy PHP
print("dla mężczyzn. Kobiety nie są tu mile widziane!"); } ?>
Zamiast używać instrukcji print, można przełączyć się do trybu HTML w każdej z dwóch gałęzi:
if (female()) ( ?> Witryna tylko dla kobiet
Witryna ta została utworzona tylko dla kobiet.
Mężczyźni nie są tu mile widziani! Witryna tylko dla mężczyzn "
"Witryna ta została utworzona tylko dla mężczyzn.
Kobiety nie są tu mile widziane!"
Wersja ta jest być może nieco trudniejsza do czytania, ale jedyną różnicą jest zamiana serii instrukcji print na blok HTML, który rozpoczyna się zamykającym znacznikiem PHP (?>) i kończy się otwierającym znacznikiem PHP(
W przykładach umieszczonych w tej książce zwykle unikamy tego rodzaju warunkowego włączania, ponieważ jest to trudniejsze do czytania dla początkujących programistów PHP. Jednak nie powinno to cię powstrzymywać. Włączanie takie powoduje znaczne przyspieszenie wykonania. W trybie HTML maszyna PHP tylko przesyła znaki, szukając otwierającego znacznika PHP. Jest to o wiele szybsze niż analiza i wykonywanie instrukcji print, szczególnie gdy zawierają ciągi w cudzysłowach.
Switch Konstrukcja switch jest bardzo użyteczna dla specyficznych rodzajów rozgałęzień. Zamiast wybierać ścieżkę obliczając wartość wyrażeń logicznych, switch bierze pod uwagę wartość jednego wyrażenia. Składnię przedstawiamy poniżej, część nieobowiązkowa otoczona jest nawiasami kwadratowymi ([]). switch (wyrażenie) (
case wartość_l: instrukcja_l instrukcja_2 [break;]
Wyrażenie może być zmienną lub innym rodzajem wyrażenia, które można zinterpretować jako wartość typu prostego (liczba lub ciąg). Konstrukcja ta oblicza wartość wyrażenia i sprawdza, czy wynik jest równy kolejnym wartościom podanym w klauzuli case. Gdy zostanie znaleziona odpowiednia wartość, wykonane będą kolejne instrukcje aż do napotkania instrukcji break lub zakończenia instrukcji switch (break może również służyć do przerywania pętli). Część default może być umieszczona na końcu instrukcji i będzie wykonana dla wszystkich wartości wyrażenia, dla których nie było odpowiedników. Przepiszmy nasz przykład dla instrukcji if: switch ($day) ( case 5:
print("Pięć złotych obraczek ");
break; case 4:
print("Cztery śpiewające ptaki ");
break; case 3: print("Trzech muszkieterów "}; break; case 2:
print("Dwie szare myszy ") ; break;
default: print("Kuropatwa na gruszy "); )
Kod ten wypisze odpowiednią linię dla wartości 2 - 5, a dla innych wartości — „Kuropatwa na gruszy". Najbardziej mylącym zachowaniem instrukcji switch jest to, że wykonywane są wszystkie instrukcje po pasującej klauzuli case, chyba, że umieścimy instrukcję break przerywającą wykonanie. W powyższym przypadku instrukcja break pozwala na wypisanie tylko jednego wiersza piosenki za jednym razem. Jeżeli usuniemy wszystkie instrukcje break, dostaniemy sekwencję wierszy aż do wiersza finałowego piosenki.
Pętle Gratulacje! Właśnie minąłeś granicę pomiędzy pisaniem skryptów a „prawdziwym programowaniem". Struktury warunkowe, które omówiliśmy, są użyteczne, ale istnieją granice ich samodzielnego użycia. Z drugiej strony istnieją podstawy teoretyczne mówiące, że każdy język z warunkami i pętlami może wykonać wszystko, co tylko może
122_________________________________________Część
l
»
Podstawy
PHP
zrobić dowolny język programowania. Nie musisz od razu pisać kompilatora za pomocą PHP, ale dobrze jest wiedzieć, że nie ma do tego wewnętrznych przeszkód.
Pętle ograniczone i nieograniczone Pętla ograniczona to pętla wykonująca się stałą liczbę razy. Patrząc na kod, możesz określić, ile razy zostanie wykonane ciało pętli, język gwarantuje liczbę przebiegów pę-
tli. Pętla nieograniczona to pętla, która wykonuje się aż do spełnienia jakiegoś warunku, warunek jest zależny od kodu wykonywanego w ciele pętli. Pętle ograniczone są
przewidywalne, natomiast nieograniczone mogą być dowolnie skomplikowane.
W przeciwieństwie do niektórych języków PHP nie posiada konstrukcji przeznaczonej tylko dla pętli ograniczonych, while, do-while oraz for są konstrukcjami nieograniczonymi, jednak, jak się okaże, pętle nieograniczone mogą robić to samo, co pętle ograniczone. \ oatrA takie
Oprócz pętli PHP dostarcza funkcji do iteracji po zawartości tablicy. Zostanie to opisane w rozdziale 11.
While Najprostszą pętlą w PHP jest while, które ma następującą składnię: while (warunek) instrukcja
Pętla while oblicza wartość wyrażenia warunkowego, traktując je jako wyrażenie logiczne. Jeżeli jest prawdziwe, wykonywana jest instrukcja ciała pętli i ponownie obliczana jest wartość warunku. Jeżeli warunek jest fałszywy, wykonywanie pętli while jest zakończone. Oczywiście jak w przypadku instrukcji if, instrukcja może być jedną
instrukcją lub blokiem.
Ciało pętli nie musi zostać wykonane, jak w przykładzie: while (FALSE) print("To nigdy nie będzie wydrukowane. ");
lub może wykonywać się „wiecznie", jak poniżej: while (TRUE)
print("TO się nigdy nie skończy. ");
albo może wykonywać się określoną liczbę razy: Scount = l; while ($count <=10) (
Ostatni przykład wydrukuje dokładnie dziesięć linii (inne interesujące przykłady znajdziesz w „Przykładach pętli" w dalszej części rozdziału).
Do-while Konstrukcja do-while jest podobna do while, poza tym, że warunek jest wykonywany na końcu pętli. Składnia jest następująca: do
instrukcj a
while (wyrażenie);
Instrukcja jest wykonywana, następnie obliczana jest wartość wyrażenia. Jeżeli wyrażenie ma wartość TRUE, instrukcja jest powtarzana, aż wyrażenie będzie miało wartość FALSE. Jedyną praktyczną różnicą pomiędzy do-while i while jest to, że ciało pętli dowhile zostanie wykonane co najmniej raz. Na przykład: Slicznik = 45; do { print("Licznik: Scount"); $count = Scount + 1; l while (Slicznik <= 10);
wydrukuje tylko jedną linię: Licznik: 45
For Najbardziej złożoną pętlą jest pętla for. Jej składnia jest następująca: for (wyrażenie_początkowe; warunek_zakońcżenią; wyrażenie_końcowe)
instrukcja
W czasie wykonywania instrukcji for, najpierw wykonywane jest wyrażenie_początkowe jeden raz; zwykle używane jest do inicjalizacji zmiennych. Następnie sprawdzany jest warunek_zakończenia, jeżeli ma wartość false, pętla się kończy, jeżeli true, wykonywana jest instrukcja ciała pętli. Na koniec wykonywane jest wyrażenie_końcowe i cykl jest powtarzany od sprawdzenia warunku zakończenia. Jak zwykle, instrukcja oznacza jedną instrukcję (zakończoną średnikiem), blok instrukcji lub instrukcję warunkową. Jeżeli przedstawimy konstrukcję for jako pętlę while, będzie wyglądała następująco: wyrażenie_początkowe; while ( w a r u n e k _ _ z a k o ń c z e n i a ) { instrukcja;
wyrażeńie_końcowe;
}
124_________________________________________Część
l
»
Podstawy
PHP
Typowa konstrukcja for posiada jedno wyrażenie początkowe, jeden warunek zakończenia i jedno wyrażenie końcowe, jednak można usunąć każdy z tych składników. Jeżeli zostanie usunięty warunek zakończenia, jest to traktowane tak, jak gdyby wstawiona została za niego wartość TRUE. Konstrukcja: for (;;)
instrukcja;
jest tożsama z: while (TRUE) instrukcja;
Można również wstawić więcej niż jeden składnik każdego typu, oddzielony przecinkiem. Warunek zakończenia będzie prawdziwy, jeżeli którykolwiek z podwarunków zostanie spełniony, tak jak przy użyciu operatora or. Poniższa instrukcja: for ($x = 1 , Sy = l, $z = 1;
Mimo że składnia for jest najbardziej skomplikowana ze wszystkich pętli, jest często używana do tworzenia prostych pętli ograniczonych przy użyciu następującego schematu: for ($licznik = 0; $licznik < Smaksimum; $licznik = Slicznik + l ) instrukcja;
Przykłady pętli Prześledzimy teraz kilka przykładów użycia pętli.
Ograniczona pętla for Na wydruku 7.1 pokazujemy typowe użycie ograniczonych pętli for. Ponieważ większość czytelników zna tabliczkę mnożenia, zamiast niej pokazujemy tabliczkę dzielenia. Strona utworzona przez program z wydruku 7.1 pokazana jest na rysunku 7.1.
print ("$count_K/TH>") ; for ($count_2 = $start_num; $count_2 <= $end_num;
$count_2++) {
Sresult = $count_l / $count_2; printf("
%.3f
", Sresult); // Popatrz do rozdziału 9
)
print("\n"); ?>
)
Rysunek 7.1.
Tabliczka dzielenia
Główną częścią tego programu są dwie zagłębione pętle. Każda z nich wykonywana jest
dziesięć razy, co w wyniku daje tabelę 10 x 10. Każdy przebieg zewnętrznej pętli wypisuje wiersz tabeli, natomiast każdy przebieg pętli wewnętrznej tworzy pojedynczą komórkę. Jedyną nowością w tym przykładzie jest użycie funkcji printf do wypisywania liczb (opisana w rozdziale 9.), która pozwala na kontrolę liczby cyfr po przecinku drukowanej liczby.
126_________________________________________Część l » Podstawy PHP
Nieograniczona pętla while Teraz zajmiemy się pętlą, która nie jest w tak oczywisty sposób ograniczona. Wyłącznym przeznaczeniem kodu z wydruku 7.2 jest przybliżenie pierwiastka z 81 (przy użyciu metody Newtona). Przybliżenie rozpoczyna się od liczby l i w kolejnych przebiegach pętli jest poprawiane, aż do osiągnięcia zadanej dokładności. Kolejne przybliżenia przedstawione są na rysunku 7.2. Wydruk 7.2. Przybliżanie pierwiastka kwadratowego______________________________
Przybliżanie pierwiastka kwadratowego
Przybliżanie pierwiastka kwadratowego
Sprecision = 0.0000001; Sguess_squared = Sguess * Sguess; while ((Sguess_squared - Starget > Sprecision) or {Sguess_squared - Starget < - Sprecision)) f print{"Bieżące przybliżenie: Sguess jest pierwiastkiem z $target "); Sguess = (Sguess + (Starget / Sguess)) / 2; $guess_squared = Sguess * Sguess;
Mimo że przykład bardzo ładnie pokazuje potencjał nieograniczonych pętli, jest jednak dosyć sztuczny: po pierwsze, ponieważ PHP posiada świetną funkcję do obliczania pierwiastka kwadratowego (sqrt); po drugie, liczba 81 jest na stałe wpisana do kodu. Nie możemy użyć tej strony do obliczania pierwiastka dowolnej liczby. W następnym rozdziale pokażemy, jak tworzyć funkcje, które pobierają jako parametr liczby. W rozdziale 12. poznasz, jak przekazywać parametry z jednej strony do drugiej.
Break i continue Normalnie pętla kończy się, gdy warunek zakończenia ma wartość FALSE. Specjalne instrukcje break i continue zapewniają alternatywny sposób wyjścia z każdej pętli. * Instrukcja break kończy najbardziej wewnętrzną pętlę, której ciało zawiera break.
* Instrukcja continue powoduje przeskoczenie do końca bieżącej iteracji w najbardziej wewnętrznej pętli, zawierającej tę instrukcję.
Na przykład poniższy fragment: for ($x - l ; Sx < 10 ; $x++) {
// jeżeli x jest nieparzyste, przerwij pętlę
if ($x % 2 1= 0}
break;
print("$x "); )
nic nie wydrukuje, ponieważ l jest nieparzysta. Spowoduje to natychmiastowe zakończenie pętli. Natomiast taki kod: for (
)
($x = l
;
$x < 10 ;
$x++)
// j e ż e l i x jest n i e p a r z y s t e , opuść ten przebieg if ($x ł 2 !- 0)
continue; print("$x ");
da w efekcie 2 4 6 8
ponieważ w efekcie działania instrukcji continue zostaną opuszczone wszystkie liczby nieparzyste. Używając instrukcji break, programista nie musi korzystać z głównego warunku zakończenia pętli. Przeanalizujmy poniższy fragment, który drukuje listę liczb pierwszych
(niepodzielnych przez żadną inną liczbę oprócz jeden i samej siebie). $limit = 500; Sto_test = 2; while(TRUE) { Stestdiv = 2;
128______________________________________Część l » Podstawy PHP if (Sto_test > $limit) break; while (TRUE) ( if (Stestdiv > sqrt(Sto_test) ) ( print "$to_test " ; break;
) // sprawdź, czy $to_test jest podzielne przez Stestdiv if ($to_test % $testdiv == 0) break;
$testdiv = $testdiv + 1;
) $to_test = Sto_test + 1; }
W kodzie tym mamy dwie zagnieżdżone pętle while, zewnętrzna przebiega przez wszystkie liczby od l do 500, wewnętrzna pętla sprawdza prawdopodobne podzielniki. Jeżeli wewnętrzna pętla znajdzie podzielnik, liczba nie jest pierwsza, więc pętla jest przerywana i nic nie drukuje. Jeżeli sprawdzanie dojdzie do pierwiastka z liczby, możemy bezpiecznie założyć, że liczba jest pierwsza i wewnętrzna pętla jest przerywana po wydrukowaniu liczby. Zewnętrzna pętla jest przerywana, gdy osiągnie granicę liczb do sprawdzenia. Wynikiem jest lista liczb pierwszych mniejszych od 500. 2 3 107 223 337 457
Zauważ, że krytyczny dla działania tego programu jest fakt, że break przerywa tylko wewnętrzną pętlę.
Pętle nieskończone Jeżeli kiedykolwiek programowałeś w innym języku, zdarzyło ci się prawdopodobnie przypadkowo stworzyć pętle nieskończone (pętla, której warunek zakończenia zawsze ma wartość TRUE, dlatego nigdy się nie kończy). Pierwszą rzeczą, jaką się wtedy robi, jest przerwanie programu, ponieważ bez interwencji z zewnątrz będzie działał „ciągle". Jednak w jaki sposób przerwać skrypt PHP? Czy wystarczy przycisnąć przycisk Stop w przeglądarce? Odpowiedź zależy od ustawień konfiguracji PHP. Możesz nakazać PHP ignorowanie przerwania z przeglądarki (wysyłane po naciśnięciu Stop), jak również ustawić ograniczenie czasu wykonywania skryptu (więc „ciągle" będzie trwało nieco krócej). Domyślna konfiguracja PHP ignoruje przerwania z przeglądarki, ale czas wykonania pojedynczego skryptu jest ograniczony do 30 sekund. Limit czasu zabezpiecza przed
przypadkowymi pętlami nieskończonymi, ale może nie działać w niektórych wersjach PHP 3 i PHP 4 beta 3. Więcej na temat konfiguracji PHP w rozdziale 31.
Składnia alternatywna PHP pozwala na inny sposób rozpoczynania i kończenia ciała instrukcji if, switch, for oraz while. Polega to na zastąpieniu początkowej klamry bloku dwukropkiem,
a zamykającej klamry specjalnym słowem kluczowym dla każdej z instrukcji (endif, endswitch, endf or oraz endwhile).
Przykładowo taka składnia instrukcji if wygląda następująco: if (wyrażenie):
Zauważ, że ciała części elseif oraz else również rozpoczynają się dwukropkiem. Alternatywna składnia while jest następująca while (wyrażenie): instrukcja; endwhile;
Możesz używać takiej składni, jaka ci przypadnie do gustu. Alternatywna składnia jest włączona do PHP ze względów historycznych i dla wygody ludzi używających jej od
wczesnych wersji programu. W całej książce będziemy konsekwentnie używać składni standardowej.
Przerywanie wykonania Czasami trzeba poddać. PHP oferuje dwie konstrukcje pozwalające na zakończenie wykonywania skryptu: 1. Konstrukcja exit ( ) nie posiada argumentów. Kończy przetwarzanie skryptu w dowolnym momencie.
2. Konstrukcja die ( ) ma ciąg znaków jako argument. Kończy przetwarzanie skryptu, wysyłając na wyjście ciąg znaków podany jako argument.
130______________________________________Część l » Podstawy PHP
Wszystko, co PHP stworzył do czasu wykonania exit { ) lub die ( ) , zostanie wysłane do klienta.
Jaki jest cel używania exit ( ) lub die ( ) ? Jedną z możliwości jest przerwanie przetwarzania strony, jeżeli skrypt zorientuje się, że nie ma już nic do wysłania, a ty nie chcesz tworzyć skomplikowanych instrukcji warunkowych. Jednak takie podejście może utrudnić czytanie i uruchamianie długich skryptów. Lepszym zastosowaniem konstrukcji die ( ) jest obsługa błędów. Dobrze jest przyzwyczaić się do sprawdzania nieoczekiwanych sytuacji, które mogą zepsuć wykonanie skryptu. Jeżeli sytuacja taka zostanie obsłużona za pomocą die ( ) , zostanie wypisany komunikat informujący o problemie. Jeżeli instrukcja wykona się prawidłowo, die ( ) nie zostanie wykonane. Rozważmy poniższy pseudokod, który zakłada, że posiadamy funkcje łączące się z bazą danych i używające tego połączenia:
$connection = make_database_connection(); if (!$connection) die ("Brak połączenia z baza. danych"); use_database_connection($connection);
W tym przykładzie założyliśmy, że funkcja make_database_connection ( ) (jak
większość funkcji PHP) zwraca użyteczną wartość, jeżeli zakończy się sukcesem, lub false, jeżeli się nie udała. Możemy napisać bardziej zwartą wersję tego przykładu, korzystając z tego, że or ma niższy priorytet niż operator przypisania. $connection = make_database_connection() or die("Brak połączenia z bazą danych"); use_database_connection($connection) ;
Taka konstrukcja działa, ponieważ operator or jest skracany, a instrukcja die ( ) będzie wykonana dopiero, gdy wyrażenie $connection = make_database_connection ( )
będzie miało wartość false. Ponieważ przypisywana wartość jest wartością przypisania, fragment działa identycznie jak poprzednia wersja.
Podsumowanie PHP posiada zestaw struktur sterujących podobny do C, które działają w zależności od wartości wyrażenia logicznego, do zbudowania którego można użyć operatorów logicznych (and, or, xor, !, & & , I I ) . Do prostego rozgałęziania kodu używamy struktur if oraz switch, pętle budujemy przy użyciu while, do-while oraz for, exit i die są używane do zakończenia wykonywania skryptu. W tabeli 7.3 zebraliśmy wszystkie struktury sterujące, opisane w tym rozdziale, oprócz
Oblicza wartość warunek i jeżeli jest true, wykonuje wyrażenie-1. Jeżeli warunek jest false i istnieje część else, wykonywane jest
if
(warunek)
wyrażenie-1 else
wyrazenie-2
w y r a ż e n i e - 2 . Konstrukcja e l s e i f jest
składniowym skrótem dla sytuacji, gdy ciałem części else jest kolejna konstrukcja if. Wyrażeniami mogą być pojedyncze instrukcje
lub
zakończone średnikiem lub blok instrukcji
if ( w a r u n e k )
otoczonych nawiasami klamrowymi
wyrażenie-1 elseif(warunek-2)
wyrażenie-2 else
wyrażenie-3
Operator
trójskładnikowy
wyrażenie-1 ?
wyrażenie-2 :
wyrażenie-3
Wykonuje wyrażenie-1 i jego wynik interpretuje
jako wartość logiczną. Jeżeli ma wartość true, , wykonywane jest wyrażenie-2, w przeciwnym wypadku wykonuje się wyrażenie-3
Switch
switch ( w y r a ż e n i e )
'
case wartość 1:
instrukc ' a~l instrukcja~2
...
[break; ]
case wartość_2: instru c^a instrukcja_4
Oblicza wartość wyrażenie i porównuje jego
wartość z wartością każdej klauzuli case. Gdy . . . ,, , zostanie znaleziona pasująca klauzula case,
rozpoczyna się wykonywanie instrukcji (włączając
w to kolejne klauzule case), aż do napotkania
break lub zakończenia instrukcji switch.
Opcjonalna klauzula default jest wykonywana, jeżeli nie ma pasujących części case
[break;]
} While
[default: instrukcja_domyślna
while ( w a r u n e k )
instrukcja
Wykonywany jest warunek i jego wartość jest
interpretowana jako wartość logiczna. Jeżeli warunek ma wartość false, wykonanie konstrukcji while jest zakończone. Jeżeli ma wartość true,
wykonywana jest instrukcja aż do momentu, gdy
warunek będzie miał wartość false. Pętla while jest przerywana, jeżeli napotkana zostanie instrukcja break; jeżeli wystąpi continue, bieżąca iteracja
jest opuszczana
Do-while
do
instrukcja
while ( w a r u n e k ) ;
Bezwarunkowo wykonywana jest instrukcja, następnie jest wykonywana aż do chwili, gdy
i u j • i •• , • warunek będzie •miał wartość false ,• (instrukcje
break i continue działają tak samo jak dla while)
132______________________________________Część
l
»
Podstawy
PHP
Tabela 7.3. Struktury sterujące PHP (ciąg dalszy)
Nazwa
Składnia
Działanie
For
f°r (wyrażenie_pocz;
Bezwarunkowo wykonywane jest
warunek_zakon; wyrazenie_ on) instrukcja
wyrażenie_pocz. Następnie, jeżeli warunek zakon ma wartość true, wykonywana , , ,
jest instrukcja i wyrażenie_kon aż do chwili, gdy warunek_zakon będzie miał wartość false. Można opuścić części instrukcji lub wstawić kilka wyrażeń, oddzielając przecinkami. Brakujące wyrażenie_kon jest traktowane jak true
(instrukcje break i continue działają tak samo
jak dla while) Exit
exit ()
Die
die ( k o m u n i k a t )
Kończy bezwarunkowo przetwarzanie skryptu Wysyła na wyjście komunikat i kończy
przetwarzanie skryptu
Rozdział 8.
Użycie i definiowanie funkcji W tym rozdziale: * Użycie wbudowanych funkcji PHP •* Przeszukiwanie dokumentacji funkcji •* Definiowanie własnych funkcji
* Zagadnienia zaawansowane: zmienna liczba argumentów, przekazywanie parametrów przez referencję, zmienne funkcyjne
Każdy prawdziwy język programowania posiada mechanizmy abstrakcji proceduralnej, sposobu na nazwanie fragmentów kodu i wykorzystywanie ich do tworzenia kolejnych fragmentów. Niektóre języki skryptowe nie posiadają tych mechanizmów; z własnego doświadczenia możemy stwierdzić, że skomplikowane skrypty szybko stają się kłopotliwe w utrzymaniu. Mechanizm PHP do zapewnienia tego rodzaju abstrakcji to funkcje. Istnieją w tym języku dwa rodzaje funkcji, wbudowane oraz definiowane przez programistę. W tym rozdziale wyjaśnimy sposób użycia funkcji dostarczanych przez PHP, a nieco
później omówimy sposób definiowania własnych. Na szczęście nie ma różnicy pomiędzy używaniem własnych i wbudowanych funkcji.
Użycie funkcji Podstawowa składnia użycia (wywoływania) funkcji jest następująca: nazwa_funkcji(wyrażenie_l, wyrażenie_2, ..., wyrażenie_n)
134_________________________________________Część l
» Podstawy PHP
Po nazwie funkcji występuje lista wyrażeń wejściowych (w nawiasach) zwanych argumentami funkcji. Funkcje mogą być wywoływane bez argumentów lub z argumentami, w zależności od definicji. Gdy PHP napotka wywołanie funkcji, na początek oblicza
wartość każdego argumentu i używa tych wartości jako dane wejściowe funkcji. Wynikiem jest wartość zwracana przez funkcję (o ile istnieje).
Wszystkie poniżej przytoczone przykłady są prawidłowymi wywołaniami wbudowanych funkcji: sqrt(9); // funkcja pierwiastek, zwraca 3 rand(10, 10+10); // liczba losowa pomiędzy 10 i 20 strlen("Tutaj znajduje się 28 znaków");
pi();
// zwraca przybliżenie liczby pi
// zwraca 28
Funkcje te były wywołane odpowiednio z l, 2 i l argumentem oraz bez argumentów.
Zwracane wartości a efekty uboczne Każde wywołanie funkcji jest wyrażeniem PHP. Istnieją dwa powody, dla których umieszcza się to wywołanie w kodzie: dla zwracanej wartości lub efektu ubocznego.
Wartość zwracana jest wartością, którą otrzymujemy przez wywołanie funkcji. Wartość możesz np. przypisać do zmiennej: ?moje_pi = p i ( i ;
Można również wbudować jaw bardziej skomplikowane wyrażenie: Sprzybl = sqrt(Sprzybl) * sqrt(Sprzybl);
Funkcje mogą być zastosowane do szerokiej gamy efektów ubocznych, takich jak: pisanie do pliku, manipulowanie bazą danych, drukowanie w przeglądarce klienta. Można również jednocześnie korzystać z efektów ubocznych i zwracanej wartości; często funkcja, podejmująca jakieś akcje, zwraca wartość określającą, czy zostały one zakończone sukcesem.
Wynik funkcji może być dowolnego typu; jeżeli funkcja zwraca wiele wyników, często korzysta się z typu tablicowego.
Dokumentacja funkcji Architektura PHP została zaprojektowana w sposób, który ułatwia rozszerzanie jej przez programistów. Podstawowy język PHP jest bardzo jasny i elastyczny, ale nie oferuje zbyt wielu możliwości. Większość siły PHP jest zawarta w wielu wbudowanych funkcjach. Można łatwo rozszerzać pakiet poprzez dodawanie nowych funkcji wbudowanych, nie zmieniając żadnych mechanizmów, z których mogliby korzystać inni użytkownicy.
Rozdział 8. » Użycie i definiowanie funkcji_____________________________135
Mimo że książka ta opisuje wiele z wbudowanych funkcji, wyjaśniając sposób użycia niektórych z nich bardzo szczegółowo, najbardziej wiarygodnym źródłem informacji
jest podręcznik dostępny pod adresem http://www.php.net. Tu wybraliśmy do szczegó-
łowego omówienia kilka tematów, a opisanie każdego aspektu PHP leży w gestii dokumentalistów. Mamy nadzieję uaktualniać książkę przed kolejnymi wydaniami, aczkolwiek to właśnie podręcznik zawsze będzie zawierał najbardziej aktualne dane na temat ciągle rosnącego zestawu funkcji. Mimo że poniższe dane były prawidłowe w czasie pisania tej książki, niektóre szczegóły mogły zostać zmienione, jeżeli przeorganizowano podręcznik.
Aby odnaleźć podręcznik, przejdź na stronę http://www.php.net i odszukaj Documenta-
tion na lewym panelu nawigacji. Strona, do której przechodzimy za pomocą tego połączenia, zawiera podręcznik w kilku rodzajach formatów. Naszym ulubionym jest podręcznik online z komentarzami, umożliwiający użytkownikom wysyłanie komentarzy do każdej strony. Należy jednak zapamiętać, że system komentowania nie służy zadawaniu pytań! Właściwym miejscem są listy dyskusyjne, wymienione na stronie
Support, dostępnej z głównej strony http://www.php.net.
Najobszerniejszą częścią podręcznika jest lista funkcji; każda funkcja posiada własną
stronę dokumentacji. Każda ze stron rozpoczyna się nazwą funkcji i krótkim opisem. Zawiera deklarację nagłówka w stylu języka C i nieco dłuższy opis działania. Podaje się również przykłady użycia oraz objaśnienia i ostrzeżenia od użytkowników.
Nagłówki w dokumentacji Dla osób nieznających języka C nagłówki funkcji, zawarte na stronach dokumentacji, mogą wydać się nieco mylące. Format nagłówka jest następujący: typ_zwracany nazwa_funkcj i(typl argl, typ2 ar2, ...);
Definiuje typ wartości zwracanej przez funkcję, nazwę funkcji oraz liczbę i spodziewane typy argumentów.
Typowym nagłówkiem jest: string substr{string string, int start [, int length]);
Oznacza to, że funkcja substr zwraca ciąg znaków i oczekuje ciągu i jednego lub dwóch liczb całkowitych jako argumentów. Nawiasy kwadratowe otaczające int length oznaczają argument opcjonalny, więc substr może być wywoływany z ciągiem znaków i liczbą lub ciągiem znaków i dwoma liczbami.
W przeciwieństwie do C typy argumentów w nagłówkach nie są absolutnie wymagane. Jeżeli wywołasz funkcję substr z liczbąjako pierwszym argumentem, nie otrzymasz
komunikatu o błędzie. W zamian PHP skonwertuje pierwszy argument do postaci ciągu.
136_________________________________________Część
l
»
Podstawy
PHP
Typy argumentów w nagłówku wskazują na intencje autora; dobrze jest wywoływać funkcję zgodnie ze specyfikacją lub wiedzieć, w jaki sposób zostanie zastosowana konwersja typów. W dokumentacji są używane nazwy sześciu podstawowych typów lub ich zamienników: integer (lub int), double (lub float, real), boolean, string, a r r a y i ob-
ject. Można spotkać dodatkowo typy void oraz mixed. Typ zwracanej wartości void oznacza, że funkcja nie zwraca żadnego wyniku, natomiast mixed oznacza dowolny typ wyniku.
Szukanie opisu funkcji Jaka jest najlepsza metoda odszukania informacji w podręczniku? Zależy to od rodzaju zadawanego pytania. Najczęściej zadawanymi pytaniami są: * Chciałbym użyć funkcji X. Jak ona działa? * Chcę zrealizować Y. Czy jest funkcja, która to wykona? Pełna wersja podręcznika zapewnia, dla pierwszego rodzaju pytań, automatyczne szukanie opisu funkcji na podstawie jej nazwy. Przycisk quick refna panelu nawigacji otwiera, po
przesunięciu nań kursora myszy, pole pozwalające na wpisanie nazwy funkcji. Kliknięcie
przycisku quick re/'przenosi nas do strony z alfabetyczną listą wszystkich funkcji.
Do drugiego rodzaju pytań najlepiej użyć organizacji hierarchicznej skorowidza funkcji. W czasie pisania tej książki był on podzielony na około 62 rozdziały. Wspomniana wcześniej funkcja substr znajduje się w części String functions. Możesz przejrzeć listę rozdziałów i przejść do tej, która najlepiej opisuje zadania, jakie masz do wykonania. Możesz również, jeżeli znasz nazwę funkcji, skorzystać z przycisku quick ref, aby szybko przeskoczyć do odpowiedniej części.
Definiowanie własnych funkcji PHP nie wymaga definiowania funkcji. Możesz tworzyć interesujące i użyteczne witryny za pomocą podstawowych konstrukcji języka i dużej liczby funkcji wbudowanych. Jednak z czasem, gdy twój kod stanie się obszerniejszy, trudniejszy do zrozumienia i kłopotliwy w zarządzaniu, powinieneś rozpocząć przenoszenie jego fragmentów do funkcji.
Czym jest funkcja? Funkcja jest sposobem na wyizolowanie części kodu i nadanie mu nazwy, dzięki czemu możliwe jest późniejsze wywołanie tego fragmentu podaniem nazwy. Funkcje są najbardziej użyteczne, jeżeli używasz kodu w więcej niż jednym miejscu. Mogą być przydatne w przypadku jednego użycia, ponieważ zapewniają większą przejrzystość kodu.
Rozdział 8. » Użycie i definiowanie funkcji_____________________________137
Składnia definicji funkcji Składnia definicji funkcji wygląda następująco: function nazwa_funkcji ($arqumentl, $argument2, .,.) {
instrukcjal; instrukcja2;
)
Definicja funkcji ma cztery części: 1. Słowo kluczowe function. 2. Nazwę, jaką nadajesz funkcji.
3. Listę parametrów funkcji — zmienne oddzielone przecinkami. 4. Ciało funkcji — blok instrukcji. Podobnie jak nazwy zmiennych, nazwy funkcji mogą składać się z liter, cyfr i podkreślenia; nie mogą rozpoczynać się cyfrą. W przeciwieństwie do zmiennych, nazwy funk-
cji są konwertowane do małych liter przed ich zapamiętaniem, więc wielkość liter nie ma znaczenia.
Gdy wywoływana jest funkcja zdefiniowana przez użytkownika, podejmowane są następujące czynności: 1. PHP na podstawie nazwy odszukuje funkcję (jeżeli nie została wcześniej zdefiniowana, wyświetli komunikat o błędzie).
2. PHP podstawia wartości argumentów wywołania (parametrów aktualnych) do zmiennych zdefiniowanych w liście parametrów (parametrów formalnych).
3. Wykonywane są instrukcje zawarte w ciele funkcji. Jeżeli jedną z instrukcji jest return, wykonanie funkcji jest zatrzymane i zwracana jest podana wartość. Jeżeli nie ma takiej instrukcji, funkcja kończy się po wykonaniu ostatniej
instrukcji bez zwracania wartości.
Doświadczeni programiści na pewno zauważyli, że powyższy opis mówi o przekazywaniu parametrów przez wartość. W ostatniej części tego rozdziału opiszemy różnice i sposób przekazywania parametrów przez zmienną.
Przykład definicji funkcji Rozważmy hipotetyczny przykład kodu, który pomaga w wyborze lepszej oferty (spośród wielu butelek napojów chłodzących). $liters_l = 1.0; $price_l = 1.59;
if ($per_literl < $per_liter2) print("Pierwsza oferta jest lepsza! "); else print("Druga oferta jest lepsza! ");
Ponieważ taki rodzaj porównania występuje bardzo często, zamieńmy ten fragment na funkcję, która może być wielokrotnie używana. Przykładem jest następujący kod: function better_deal ($amount_l, Sprice_l,
$price_2 = 2.09; if better_deal($liters_l, $price_l,
$liters_2, Sprice_2) print("Pierwsza oferta jest lepsza! "); else printC'Druga oferta jest lepsza ! " );
Funkcja better_deal wydziela trzy wiersze z poprzedniego kodu, zawierające przeliczenie i porównanie. Funkcja wymaga czterech argumentów i zwraca wartość logiczną. Można jej użyć jako składnika instrukcji if. Mimo że funkcja jest dłuższa niż oryginalny kod, taka zamiana przynosi następujące korzyści: można użyć tej funkcji w wielu miejscach; jeśli zmienimy sposób przeliczania, zmiany trzeba nanieść tylko w jednym miejscu. Jeżeli jedynym zastosowaniem takiego porównania cen jest wypisanie lepszej oferty, można zawrzeć drukowanie w ciele funkcji: function print_better_deal ($amount_l, Sprice_l,
$amount_2, $price_2)
{
$per_amount_l = $price_l / $amount_l;
$per_amount_2 = $price_2 / $amount_2;
if ($per_amount_l < $per_amount_2)
print("Pierwsza oferta jest lepsza! ");
else
printC'Druga oferta jest lepsza ! " ) ; l $liters_l = 1.0;
Nasza pierwsza funkcja zwracała, przy użyciu instrukcji return, wartość wyrażenia logicznego, którego użyto w warunku instrukcji if. Druga funkcja nie posiada instrukcji . return, ponieważ używana jest tylko ze względu na jej efekt uboczny — drukowanie tekstu w przeglądarce klienta. Gdy zostanie wykonany ostatni wiersz funkcji, PHP będzie kontynuował wykonanie programu od następnego wiersza po wywołaniu funkcji.
Rozdział 8. » Użycie i definiowanie funkcji_______________________________139
Parametry formalne i parametry aktualne W poprzednich przykładach argumenty przekazywane do funkcji były zmiennymi (chociaż nie jest to wymagane). Parametry aktualne (to znaczy argumenty wywołania funkcji) mogą być dowolnymi wyrażeniami posiadającymi wartość. W przykładzie możemy przekazać liczby zamiast zmiennych: print_better_deal(1.0,
1.59,
1.5,
2.09);
Zauważ, że podajemy przykłady, w których parametry aktualne mają takie same nazwy jak parametry formalne (na przykład $price_l), oraz takie, w których nazwy są różne ($liters_l). Jak się przekonamy za chwilę, parametry formalne funkcji są zupełnie
niezależne od reszty programu, nawet od wywołania funkcji.
Nieprawidłowa liczba argumentów Co stanie się, jeżeli wywołasz funkcję ze zbyt małą bądź zbyt dużą liczbą argumentów? Jak można się spodziewać, PHP nie zareaguje błędem przy standardowych ustawieniach
kontroli błędów. Jeżeli wywołasz funkcję z niedostateczną liczbą parametrów, PHP potraktuje niewypełnione parametry formalne tak samo jak niezainicjowane zmienne. Jeżeli wstawisz zbyt dużo parametrów, zbędne zostaną po prostu zignorowane. Pod koniec rozdziału opiszemy, jak wykorzystać tę tolerancję do tworzenia funkcji o zmiennej liczbie argumentów.
Funkcje a zasięg zmiennych W rozdziale 5. opisywaliśmy zasady zasięgu zmiennych: zmienne zainicjowane w pliku będą dostępne do końca. Zasady te nieco się komplikują przy definiowaniu zmiennych. Podstawowa zasada rządząca zmiennymi w ciele funkcji brzmi: każda funkcja jest odrębną jednostką. Oznacza to, że, poza specjalnymi deklaracjami, zmienne w ciele funkcji nie mają nic wspólnego ze zmiennymi o takiej samej nazwie poza funkcją. Nie jest to błąd — to bardzo pożyteczna cecha, funkcje mogą być używane wielokrotnie w wielu
miejscach programu, więc muszą być niezależne od kontekstu, w którym są wywołane. W innym przypadku spędziłbyś wiele czasu, szukając błędów spowodowanych użyciem
zmiennej o tej samej nazwie w różnych fragmentach kodu.
Jedynymi zmiennymi, do których może odwoływać się zmienna, są zmienne parametrów formalnych oraz zmienne przypisane w ciele funkcji. Możesz więc używać zmiennych lokalnych funkcji bez obawy o jej zewnętrzne działanie. Dla przykładu rozważmy następującą definicję funkcji i jej użycie: function SayMyABCs () (
Scount = 0; while ($count < 10) {
print(chr(ord('A1) + $count));
140_________________________________________Część l »
Funkcja SayMyABCs ( ) drukuje sekwencję liter (funkcje chr ( ) i ord ( ) konwertują pomiędzy literami a ich kodami ASCII). Wynikiem działania jest: ABCDEFGHIJ
Znam teraz 10 liter
Teraz wykonałem l wywołanie funkcji. ABCDEFGHIJ
Znam teraz 10 liter Teraz wykonałem 2 wywołanie funkcji.
Zarówno definicja funkcji, jak i kod poza funkcją używają zmiennej o nazwie $ count, jednak są to zupełnie różne, niekolidujące ze sobą zmienne. Zmienne zainicjowane w ciele funkcji domyślnie nie mają wpływu na resztę kodu, są tworzone na nowo przy każdym wywołaniu funkcji. Obie te własności można zmienić za pomocą specjalnej deklaracji.
Zmienne globalne i lokalne Zmienne definiowane w ciele funkcji domyślnie są lokalne. Używając deklaracji global,
można zdecydować, że zmienna będzie miała takie samo znaczenie jak na zewnątrz funkcji. Definicja taka składa się ze słowa global oraz listy zmiennych oddzielonych przecinkami, zakończonej średnikiem. Aby zobaczyć efekt działania tej deklaracji, użyjmy poprzedniego przykładu. Różnica polega na użyciu deklaracji zmiennej $count jako zmiennej globalnej oraz usunięciu początkowego zerowania w ciele funkcji: function SayMyABCs2 () ( global Scount; while (Scount < 10) ( print(chr(ord('A1) + Scount)); Scount = Scount + 1; } print(" Znam teraz Scount liter "); }
Znam teraz 10 liter Teraz wykonałem 11 wywołanie funkcji.
r Rozdział 8. » Użycie i definiowanie funkcji_____________________________141 Znam teraz 11 liter Teraz wykonałem 12 wywołanie funkcji.
Zachowanie to jest nieprawidłowe z winy deklaracji globalnej zmiennej $count. Teraz w programie istnieje tylko jedna taka zmienna, która jest zwiększana zarówno wewnątrz, jak i na zewnątrz funkcji. Gdy funkcja SayMyABCs2 { ) zostanie wywołana po raz drugi, wartość tej zmiennej wyniesie 11 i program nie wykona pętli. Mimo że przykład ten ukazuje global w złym świetle, deklaracja taka może być użyteczna. PHP posiada mechanizm (opisany w rozdziale 12.) przypisywania kilku zmiennych do każdej strony przed wykonaniem jakiegokolwiek kodu. Można łatwo uzyskać dostęp do tych zmiennych w funkcji, bez konieczności przekazywania ich jako parametry.
Zmienne statyczne Zmienne lokalne funkcji są tworzone na nowo za każdym wywołaniem funkcji. Aby zmienić ten mechanizm można, użyć deklaracji static, która powoduje, że zmienna zapamięta wartość pomiędzy kolejnymi wywołaniami tej samej funkcji. Przy użyciu tej deklaracji zmodyfikujemy naszą wcześniejszą funkcję: function SayMyABCs3 O f static $count = 0; // przypisanie tylko za pierwszym razem Slimit = Scount + 10; while (Scount < $limit) (
Znam teraz 10 liter Teraz wykonałem l wywołanie funkcji. KLMNOPQRST
Znam teraz 20 liter Teraz wykonałem 2 wywołanie funkcji.
Słowo kluczowe static powoduje, że pierwsze przypisanie zachodzi, jeśli funkcja nie była wcześniej wywoływana. Za pierwszym wywołaniem SayMyABCsS ( ) lokalna wersja $count jest zerowana. Za drugim wywołaniem zmienna będzie miała już wartość z poprzedniego wywołania. Zauważ, że zmiany zmiennej $ count na zewnątrz funkcji nie mają wpływu na lokalną wartość zmiennej.
142______________________________________Część l » Podstawy PHP
Zasięg funkcji Mimo że zasady rządzące zasięgiem zmiennych sąjasne i proste, zasady zasięgu funkcji
są jeszcze prostsze. W PHP 4 istnieje tylko jedna zasada: funkcje mogą być zdefiniowane tylko raz w skrypcie, który używa tej funkcji (zajrzyj do opisu nowej funkcji, do omówienia pomiędzy wersjami PHP). Zasięg zmiennych jest domyślnie globalny, więc funkcja zdefiniowana w skrypcie jest dostępna we wszystkich jego miejscach. Dla większej przejrzystości dobrze jest definiować funkcje na początku skryptu, przed używającym ich kodem. •4^Lj. funkcja '
W PHP 3 funkcje mogły być używane jedynie po ich definicji. Oznaczało t0 ze na bez iecznie ' J P Jszą praktyką było zdefiniowanie wszystkich funkcji (lub włączenie ich definicji) na początku skryptu, przed ich użyciem. PHP 4 prekompiluje skrypty przed ich uruchomieniem, w związku z tym ich definicje są znane wcześniej. Pozwala to na umieszczenie definicji funkcji i kodu w dowolnej kolejności, pod warunkiem jednokrotnego wystąpienia definicji każdej z funkcji.
Include oraz require Często używa się tego samego zestawu zmiennych w wielu stronach witryny WWW.
Zwykle jest to realizowane poprzez użycie include bądź require, które to instrukcje
pozwalają na zaimportowanie zawartości innego pliku do pliku wykonywanego. Użycie
jednej z powyższych instrukcji jest wskazane do klonowania definicji funkcji pomiędzy stronami, ponieważ zmienia się definicję tylko w jednym miejscu. Na początku pliku wstawiasz np. wiersze: include "proste-funkcje.inc"; include "zaawansowane-funkej e.inc"; ( ... kod używający prostych i zaawansowanych funkcji ... )
które importują dwa różne pliki z definicjami funkcji. Nawiasy nie są obowiązkowe zarówno w include ( ) , jak i require ( ) . Jeżeli pliki te zawierają tylko definicje funkcji, kolejność włączania nie ma znaczenia. Zarówno include, jak i require pozwalają na łączenie zawartości plików w miejscu ich wywołania. W przeciwieństwie do include, instrukcja require nie wykona się więcej niż raz, nawet jeżeli będzie wykonywana w pętli. PHP podstawia zawartość pliku tylko przy pierwszym wywołaniu. Niestety require nie jest magicznym rozwiązaniem problemu wielokrotnej definicji tej samej funkcji. Instrukcja ta nie potrafi skontrolować innych wywołań require i include. Jeżeli dwa razy powtórzymy w kodzie instrukcję require, żądany plik zostanie załadowany dwa razy, definiując dwukrotnie zawarte w nim funkcje. Podobna sytuacja zachodzi, gdy pliki z prostymi i zaawansowanymi funkcjami, użyte w przykładzie, korzystają z tego samego pliku z podstawowymi funkcjami za pomocą require.
Rozdział 8. » Użycie i definiowanie funkcji_____________________________143
W tym przypadku również wystąpi błąd wielokrotnego definiowania funkcji, ponieważ podstawowe funkcje zostaną załadowane dwa razy.
Jedną z prostych technik unikania wielokrotnego ładowania funkcji jest umieszczenie instrukcji include w instrukcji if, np.: if (!IsSet($myfuncs^loaded)) include ("myfuncs.inc");
$myf uncs_loaded jest zmienną ustawianą w pliku myfuncs.inc.
Rekurencja Niektóre języki kompilowane, jak np.: C i C++, nakładaj ą skomplikowane ograniczenia kolejności definiowania funkcji. Aby skompilować funkcję, kompilator musi znać wszystkie wywoływane funkcje, co oznacza, że muszą być one wcześniej zdefiniowane.
A jeśli funkcje się wzajemnie wywołują? Takie problemy spowodowały oddzielenie przez projektantów C deklaracji funkcji (prototypów) od ich definicji (implementacji). Idea tego podziału była następująca: deklaracje informują kompilator o typach argumentów i typie zwracanej wartości, co wystarcza kompilatorowi na poprawne przetworzenie definicji w dowolnym porządku. W PHP problem ten zniknął, więc nie ma prototypów funkcji. W PHP 3 funkcje musiały być zdefiniowane przed ich użyciem, lecz definiowanie w jednej funkcji wywołania innej nie jest liczone jako użycie funkcji. Gdy PHP 3 napotyka definicję funkcji A, nie oponuje, jeżeli ciało funkcji A zawiera wywołanie funkcji B, która jeszcze nie jest zdefiniowana. Funkcja B musi być zdefiniowana, gdy wywołana jest funkcja A. W PHP 4 w ogóle problem kolejności definicji nie istnieje Funkcje rekurencyjne (wywołujące same siebie) nie sprawiają więc trudności. Dla przykładu zdefiniujemy funkcję rekurencyjną i wywołamy ją. function countdown (Snum_arg) f if ($num_arg > 0) { print("Odliczamy: $num_arg ");
144_________________________________________Część l
»
Podstawy PHP
Istotne jest, czy funkcja posiada część podstawową (gałąź nierekurencyjną) i część rekurencyjną, a także czy część podstawowa na pewno zostanie wykonana. Jeżeli część podstawowa nie jest nigdy wykonywana, mamy sytuację podobną do pętli while z warunkiem zawsze spełnionym, nieskończoną pętlę wywołań funkcji. Z analizy przykładowej funkcji wiemy, że część podstawowa zostanie wykonana, ponieważ każde rekurencyjne wywołanie zmniejsza wartość przekazywanej liczby, która w końcu będzie równa zero. Oczywiście zakładamy, że liczba jest dodatnią liczbą całkowitą, a nie liczbą ujemną bądź liczbą double. Zauważ, że warunek „większy od zera" zabezpiecza przed nieskończoną rekurencją nawet w takich przypadkach, gdy warunek „różny od zera" tego zabezpieczenia nie zapewnia. Funkcje wzajemnie rekurencyjne działają podobnie (funkcje wywołujące się wzajemnie). function countdown_first (
W wyniku otrzymamy: Odliczan Odliczan Odliczan Odliczan Odliczan
e e e e e
(pierwsze): 5 (drugie): 4 (pierwsze): 3 (drugie): 2 (pierwsze): l
Zagadnienia zaawansowane Zajmiemy się teraz bardziej zaawansowanymi zagadnieniami dotyczącymi funkcji: sposobami użycia zmiennej liczby argumentów, modyfikacji przekazanych zmiennych oraz użyciem funkcji jako wartości zmiennych. W zasadzie jest to część przeznaczona dla zaawansowanych programistów ze względu na złożoność zagadnień.
Rozdział 8. » Użycie i definiowanie funkcji_____________________________145
Zmienna liczba argumentów Liczba argumentów przekazanych do zmiennej powinna zależeć od sytuacji, w której funkcja jest wywoływana. W PHP 4 istniej ą cztery sposoby obsłużenia takiej sytuacji: 1. Definicja funkcji z argumentami domyślnymi. Jeżeli brakuje argumentu w wywołaniu funkcji, branajest wartość domyślna, ostrzeżenie nie jest drukowane. 2. Użycie jako argumentu tablicy. Kod wywołujący musi wstawić potrzebne elementy do tablicy, wymagana jest również ich prawidłowa interpretacja w ciele funkcji.
3. Użycie funkcji dla zmiennej liczby argumentów (func_num_args ( ) , func_ get_arg ( ) i func_get_args ( ) ) wprowadzonych do PHP 4.
Argumenty domyślne Aby zdefiniować funkcję z argumentami domyślnymi, należy zmienić nazwę parametru formalnego na wyrażenie przypisania. Jeżeli wywołanie będzie miało mniejszą liczbę argumentów niż w definicji funkcji, PHP skojarzy wszystkie parametry aktualne z formalnymi, brakującym parametrom formalnym przyporządkuje wartości domyślne. Poniższa funkcja ma zdefiniowane wartości domyślne dla wszystkich parametrów: function tour_guide(Scity = "Gotham City",
tour_guide("Chicago", "wspaniałe miasto", "przez kilka milionów"}; tour_guide("Chicago", "wspaniałe miasto", "przez kilka milionów", "miłych ludzi");
Wynik działania tego fragmentu programu jest pokazany poniżej. Gotham City to rozległa metropolia zamieszkała przez wielu opryszków. Chicago to rozległa metropolia zamieszkała przez wielu opryszków.
Chicago to wspaniałe miasto zamieszkałe przez wielu opryszków. Chicago to wspaniałe miasto zamieszkałe przez kilka milionów opryszków. Chicago to wspaniałe miasto zamieszkałe przez kilka milionów miłych ludzi.
Głównym ograniczeniem argumentów domyślnych jest fakt, że kojarzenie parametrów formalnych z aktualnymi bazuje na kolejności argumentów. Oznacza to, że nie ma możliwości przypisania wartości do końcowych parametrów przy użyciu argumentów domyślnych i wartości domyślnych parametrów początkowych.
146_________________________________________Część l
»
Podstawy PHP
Tablice jako substytut wielu argumentów Jeżeli brak elastyczności wielu argumentów funkcji przeszkadza ci, możesz w zamian użyć tablicy jako kanału komunikacyjnego. Poniższy przykład korzysta z tej techniki. Zastosowaliśmy dodatkowo kilka sztuczek, takich jak: operator trójskładnikowy (wprowadzony w rozdziale 7.) oraz tablica asocjacyjna (wspomniana w rozdziale 6. i dokładnie opisana w rozdziale 11.). function tour_brochure(Sinfo_array) { Scity = IsSet($info_array['city1 ] ) ?
print("Scity to Sdesc zamieszkała $how_many $of_what. "};
Funkcja sprawdza zawartość tablicy dla czterech indeksów, reprezentowanych przez odpowiednie fragmenty zdania. Przy użyciu operatora trójskładnikowego przypisywane są do zmiennych wartości, przypisane do odpowiednich komórek tablicy, lub wartości domyślne. Teraz wywołamy funkcję na kilka różnych sposobów: tour_brochure(array()); // pusta tablica $tour_info = array( 'city' => 'Cozumel', 'desc1 => 'cel ucieczki', 'of_what' => 'dobrych ludzi'); tour_brochure( Stour_info );
W przykładzie tym wywołamy funkcję tour_brochure z pustą tablicą (brak argumentów) oraz z trzema z czterech możliwych wartości asocjacyjnych. Wynik działania
tego fragmentu jest następujący:
Gotham City to rozległa metropolia zamieszkała przez wielu opryszków. Cozumel to cel ucieczki zamieszkały przez wielu dobrych ludzi.
W obu przypadkach fragment „przez wielu" pochodzi z domyślnych wartości parametrów, ponieważ nic nie zostało przypisane do komórki tablicy identyfikowanej przez „how_many".
Wiele argumentów w PHP 4 PHP 4 posiada funkcje, które, użyte w ciele funkcji, pozwalają na sprawdzenie liczby przekazanych argumentów oraz odczytanie ich wartości. f unc_num_args ( )
Nie posiada parametrów. Zwraca liczbę parametrów przekazanych do funkcji.
Rozdział 8. » Użycie i definiowanie funkcji_____________________________147
f unc_get_arg ( ) Jako argument pobiera liczbę całko witą n i zwraca «-ty argument przekazany do funkcji. Argumenty są numerowane od 0.
f unc_get_args ( )
Nie posiada argumentów. Zwraca tablicę zawierającą wszystkie argumenty przekazane do funkcji. Pierwszy argument znajduje się w komórce o indeksie 0.
Każda z tych funkcji, wywołana na zewnątrz, spowoduje wygenerowanie ostrzeżenia. f unc_get_arg ( ) spowoduje ostrzeżenie, jeżeli będzie wywołana z argumentem większym od liczby argumentów przekazanych do funkcji. PHP nie wygeneruje ostrzeżeń, jeżeli funkcja zostanie wywołana z większą liczbą parametrów, niż wynika to z jej definicji. Możesz zdefiniować funkcję bez parametrów i używać opisanych wcześniej funkcji do pobierania wartości przekazanych parametrów. Jako przykład podaliśmy dwie funkcje zwracające tablicę argumentów, które zostały do nich przekazane: function args_as_array_l () { $arg_count = func_num__args () ; $counter = 0:
) function args_as_array_2 {) ( return(func_get_args()); }
Pierwsza dłuższa funkcja używa f unc_get_arg ( ) do odczytania każdego argumentu w pętli ograniczonej przez wartość odczytaną przez f unc_num_args ( ) , co zapewnia odczytanie dokładnie tylu wartości argumentów, ile podano przy wywołaniu funkcji. Każdy argument jest indywidualnie zapamiętywany w tablicy, którajest wynikiem działania funkcji. Taki sam schemat działania jest wykonywany przez funkcję func_get_ args ( ) , więc druga funkcja jest krótka. Przepiszmy teraz naszą funkcję tour_guide ( ) tak, aby skorzystać z funkcji do odczytywania wartości parametrów, a nie z argumentów domyślnych: function tour_guide_2(} { Snum_args = func_num_args();
$city = $num_args > O ? func_get_args(0) : "Gotham City"; $desc = $num_args > l ?
148___________________________________________Część l » Podstawy PHP print("$city to Sdesc zamieszkała 3how_many $of_what. "); ( tour_guide_2();
Funkcja ta działa identycznie, jak jej poprzednia wersja, i posiada te same ograniczenia. Argumenty są kojarzone ze sobą na podstawie ich kolejności, więc nie ma sposobu na zmianę „opryszków" na cokolwiek innego, przy domyślnej wartości „Gotham City".
Wywołanie przez wartość a wywołanie przez referencję Standardowo PHP przekazuje parametry za pomocą techniki nazywanej „wywołaniem przez wartość". Oznacza to, że gdy przekazujesz zmienną do funkcji, PHP tworzy kopię wartości zmiennej i przekazuje ją do funkcji. Wynik działania funkcji nie ma wpływu na wartość zmiennej przekazanej jako aktualny parametr funkcji. Jest to dobre zabezpieczenie, jeżeli używasz tylko wartości zwracanej przez funkcję, ale może być źródłem problemów, jeżeli chcesz, by zmieniła się wartość przekazywanego parametru. Zademonstrujemy teraz wywołanie przez wartość przy bardzo słabej i niewydajnej implementacji odejmowania: function lame_subtract ($numl, Snum2) ( if (Snuml < Snum2)
die("Liczby ujemne nie są obsługiwane"); $return_result = 0;
Upewnijmy się, że funkcja za każdym razem da identyczny wynik (dla tych samych danych):
Wynik It 138 Wynik 2: 138
Mimo że lame_subtract zmienia wartość parametru formalnego $numl, zmienna ta przechowuje kopię wartości zmiennej $f irst_op, więc $f irst_op nie zmieni się.
Wywołanie przez referencję PHP zapewnia dwa różne sposoby modyfikacji parametrów funkcji: w definicji lub w wywołaniu.
Jeżeli chcesz zdefiniować funkcję działającą bezpośrednio na przekazywanych zmiennych, umieść znak & przed parametrem formalnym w definicji, np.:
Rozdział 8. » Użycie i definiowanie funkcji_____________________________149 function lame_subtract_ref (&$numl, &$num2} { if ($numl < $num2)
die("Liczby ujemne nie są obsługiwane"); $return_result = 0; while ($numl > Snum2) { $numl = $numl - 1; $return_result = $return_result + 1; )
Jeżeli wykonamy powtórnie to samo odejmowanie, otrzymamy w wyniku: Wynik 1: 138 Wynik 2: O
Dzieje się tak, ponieważ parametr formalny $numl odwołuje się do tej samej liczby, co parametr aktualny $f irst_op, a zmiana jednej zmiennej powoduje zmianę drugiej. Funkcja może pobierać argumenty przez referencję. Aby to wywołać, umieść znak &
przed parametrem aktualnym. Możemy użyć oryginalnej funkcji, przekazującej parametry przez wartość i uzyskać efekt przekazania przez referencję: $first_op = 493; $second_op = 355; $resultl = lame_subtract(s$first_op, S$second_op); print("Wynik 1: $resultl "); $result2 = lame_subtract(&$first op, &$second_op); print("Wynik 2:~$result2 ");
co w efekcie da: Wynik 1: 138
Wynik 2: O
Można również używać referencji do wywołań funkcji i do zmiennych. Przypisanie referencji (&$nazwa) do innej zmiennej spowoduje, że te dwie zmienne są synonimami, a nie dwiema osobnymi zmiennymi z taką samą zawartością. Na przykład: $name_l = "Manfred von Richthofen"; $name^2 = "Percy Blakeney"; Salias_l = $name_l; // zmienne mają tę samą wartość $alias_2 = &$name_2;
// zmienne są. tym samym
$alias_l = "The Red Baron"; // nie zmienia oryginalnej zmiennej $alias_2 = "The Scarlet Pimpernel"; // zmienia oryginalna zmienna
print ("$alias_l to $name_KBR>") ; print ("Salias_2 to $name_2 ");
da w efekcie: The Red Baron to Manfred von Richthofen
The Scarlet Pimpernel to The Scarlet Pimpernel
150_________________________________________Część l » Podstawy PHP
Zmienne jako nazwy funkcji Jedną ze sztuczek, jaką można zastosować w PHP, jest użycie zmiennej zamiast nazwy funkcji zdefiniowanej przez programistę. Zamiast wpisywać nazwę funkcji, umieszczasz w kodzie zmienną. Uruchomiona zostanie funkcja o takiej nazwie, jaką wartość będzie miała zmienna. Sztuczka ta jest znana zaawansowanym programistom C i użytkownikom języka Lisp (na przykład Scheme lub Common Lisp). W poniższym przykładzie wywołania funkcji są tożsame: function customized_greeting{) ( print ("Bądź powitany!"); ) customized_greeting{);
Wykonanie tego fragmentu da w efekcie: Bądź powitany! Bądź powitany!
Ponieważ nazwy funkcji są po prostu ciągami, mogą być argumentem lub wynikiem działania funkcji.
Bardziej skomplikowany przykład Spójrzmy teraz, w jakie kłopoty możemy popaść, używając niektórych bardziej zaawansowanych własności funkcji (np. nazw funkcji jako argumentów wywołania). Na wydruku 8.1 zamieściliśmy przykład implementacji szyfrowania przez podstawianie — podstawowego rodzaju, który szyfruje komunikaty, zamieniając litery jednego alfabetu na inny. Kod ten jest dłuższy i bardziej skomplikowany niż wszystkie dotychczasowe przykłady. Możesz go opuścić, jeżeli nie chcesz zagłębiać się w szczegóły. Wydruk 8.1. Szyfrowanie przez podstawianie__________________ ____ /* Część l - algorytm szyfrowania i funkcje usługowe*/ function add_l ($num) ( return(($num + 1) % 26);
} function sub_l ($num) f return((Snum + 25) * 26); )
function swap_2 ($num) { if ($nura % 2 == 0)
___
Rozdział 8. » Użycie i definiowanie funkcji_______________________________151 return($num + 1); else return{$num - 1); } function swap_26 ($num) <
return (25 - $num);
) function lower_letter(Schar_string) (
return ((ord($char_string) >= ord('a')) && (ord ($char_string) <= ord (' z ')))/'
) function upper_letter($char_string) (
return {(ord($char_string) >= ord('A')) &&
}
(ord(Schar_string) <= ord('Z')));
/* Część 2 - funkcje szyfrowania liter*/
function letter_cipher ($char_string, $code_func) { if (!(upper_letter($char_string) I I lower_letter($char_string)}) return($char_string) ; if (upper_letter($char_string)) 3base_num = ord('A'); else $base_num = ord('a'); $char_num = ord($char_string) - $base_num;
return(chr($base_num + ($code_func($char_num) % 26))}; ) /* Część 3 - główna funkcja szyfrowania ciągu */ function string_cipher($message, $cipher_func) ( $coded_message = ""; Smessage_length = strlen(Smessage);
for ($index = 0; $index < $message_length; $index++)
Kod pokazany wydruku 8.1 składa się z trzech części. W pierwszej zdefiniowaliśmy kilka funkcji działających na liczbach od O do 25, które reprezentują litery od A do Z naszego
szyfru. Funkcja add_l dodaje l do podanej liczby modulo 26 (co oznacza, że liczby 26 i większe są „zawijane" i rozpoczynają znów od zera). O jest zamieniane na l, l na 2, ..., a 25 jest zamieniane na 0. Sub_l przesuwa liczby w odwrotnym kierunku, dodając 25 (co
w arytmetyce modulo jest odpowiednikiem odjęcia 1). Swap_2 zamienia miejscami pary liczb: O na l, l na O, 2 na 3, 3 na 2 itd. Swap_26 zamienia małe liczby na duże (25 na O, O na 25, 24 na l, l na 24 itd.). Każda z tych funkcji jest podstawą szyfrowania. Dodatkowo mamy kilka funkcji sprawdzających, czy znak jest wielką czy małą literą. Część drugą stanowi jedna funkcja letter_cipher ( ) , która za pomocą funkcji z pierwszej części koduje pojedynczy znak. Na początek sprawdza, czy podany ciąg składa się z liter (powinien składać się z jednej litery); jeżeli nie, zwraca go bez szyfrowania.
152_________________________________________Część l » Podstawy PHP
Jeżeli znak jest literą, zamieniany jest na liczbę za pomocą funkcji ord ( } . Odejmowana jest od niego wartość ASCII liter 'A' bądź 'a', co sprowadza liczbę do przedziału O -
25. Jeśli liczba znajduje się w tym przedziale, jest szyfrowana, konwertowana z powrotem do postaci litery i zwracana.
Trzecia część to funkcja string_cipher ( ) , która zwraca w postaci zaszyfrowanej ciąg podany jako parametr. Używa kilku funkcji nieopisanych do tej pory (na przykład operatora łączenia ciągów .=, który omówimy w rozdziale 9.). Funkcja ta tworzy nowy
ciąg z ciągu podanego jako parametr, szyfrując każdą literę za pomocą funkcji $cipher_func().
Teraz napiszmy program używający funkcji string_cipher ( ) : $original = "Zaszyfrowany komunikat to ABCDEFG"; print("Ciąg oryginalny to: $original "); $coding_array = array('add_l', 1sub~l', 1swap_2', 'swap_26'); for (Scount = 0; Scount < sizeof($coding_array); $count++) ( $code = $coding_array[Scount]; $coded_message = string_cipher($original, $code);
print("Zakodowane $code to: Scoded_message "); )
W tym testowym kodzie zapamiętaliśmy w tablicy nazwy czterech predefiniowanych
funkcji, szyfrujących litery i zakodowaliśmy ciąg zawarty w zmiennej Soriginal za pomocą pętli. Wynik działania tego fragmentu jest następujący: Ciąg oryginalny to: Zaszyfrowany komunikat to ABCDEFG
Zakodowane add_l to: Abtazgspxboz Ipnvojlbu up BCDEFGH Zakodowane sub_l to: Yzryxeqnvzmx jnltmhjzs sn ZABCDEF Zakodowane swap_2 to: Ybtyzeqpxbmz Ipnvmjlbs sp BADCFEH
Zakodowane swap_26 to: Azhabuildzmb plnfmrpzg gl ZYXWVUT
Możemy napisać funkcję, która stosuje więcej niż jeden sposób szyfrowania w ciągu.
Funkcja ta korzysta z funkcji odczytywania wartości argumentów w PHP 4. function chained_code ($message) f /* Pobiera ciąg oraz dowolną liczbę nazw funkcji kodujących, zwraca wynik zastosowania w ciągu wszystkich metod */ $argc = func_num_args() ;
Pierwszym argumentem chained_code ( ) powinien być ciąg do szyfrowania, następnym dowolna liczba nazw funkcji szyfrujących. Zakodowany ciąg jest wynikiem użycia pierwszej funkcji szyfrującej, następnie drugiej funkcji — w ciągu wynikowym itd. Możemy przetestować tę funkcję przy użyciu różnych kombinacji funkcji szyfrujących.
Rozdział 8. » Użycie i definiowanie funkcji_____________________________153 Stricky = chained__code (Soriginal, 1 t 1
add_l', swap_26'/ add_l', 'swap_2');
print("Zakodowana wersja to $tricky "); $easy = chained_code(Soriginal, 'add_l', 'swap_26', 1 swap_2', 'sub_l', 1 add_l', 'swap_2', 'swap_26', 'sub_l'); print("Zakodowana wersja to $easy ");
Daje to w efekcie:
Zakodowana wersja to Bygbavjkcyna okmenqoyh hk YZWXUVS
Zakodowana wersja to Zaszyfrowany komunikat to ABCDEFG
Pierwsza wersja zakodowania ciągu jest kombinacją poprzednich kodowań, jednak nie jest dokładnym odpowiednikiem żadnego z pojedynczych kodowań. Druga wersja jest jeszcze bardziej skomplikowaną kombinacją funkcji, jednak daje niezmieniony komunikat! Nie oznacza to, że nasze funkcje szyfrujące nie działają. Morał naszej kryptograficznej opowieści jest taki: ponieważ kod szyfrujący jest nieco
skomplikowany, warto skorzystać z przekazywania nazw funkcji jako argumentów funkcji.
Podsumowanie Wartość PHP jest ukryta w dużej liczbie funkcji wbudowanych, dostarczonych przez armię programistów PHP. Każda z nich jest udokumentowana (nawet zwięźle) w podręczniku, pod adresem http://www.php.net. Możesz również pisać własne funkcje, używane dokładnie w ten sam sposób, co funkcje wbudowane. Funkcje pisze się za pomocą
prostej składni w stylu C:
function moja_funkcja( $argl, $arg2, ...) f wyrażeniel;
wyrażenie2;
return ($wartość);
)
Funkcje mogą używać argumentów dowolnego typu, mogą również zwracać dowolnego typu argumenty, które nie muszą być deklarowane. Kolejność deklaracji funkcji i wywołania funkcji nie ma znaczenia, ale funkcja powinna być zdefiniowana tylko raz. Nie ma potrzeby oddzielania deklaracji funkcji lub ich prototypów. Zmienne zainicjowane w funkcji są zmiennymi lokalnymi funkcji, chyba że są zadeklarowane jako globalne. Zmienne lokalne mogą być zadeklarowane jako statyczne, co oznacza, że przechowuj ą wartość pomiędzy kolejnymi wywołaniami funkcji. Domyślnym sposobem przekazywania argumentów jest wywołanie przez wartość. Oznacza to, że funkcje pracują na kopiach argumentów, dlatego nie mogą zmodyfikować wartości oryginalnych. Możesz ustawić przekazywanie przez wartość, poprzedzając pa-
154_________________________________________Część
l
»
Podstawy
PHP
rametr znakiem & w wywołaniu albo w definicji funkcji. Nazwy wywoływanych funkcji mogą być ustalane w czasie pracy programu poprzez użycie zmiennej jako nazwy funkcji — pozwala to na traktowanie funkcji jak danej i przekazywanie jej jako parametru innych funkcji.
Rozdział 9.
Ciągi i funkcje operujące na ciągach W tym rozdziale: * Tworzenie ciągów i manipulowanie nimi + Sprawdzanie, porównywanie i przeszukiwanie ciągów * Zaawansowane operacje na ciągach przy użyciu wyrażeń regularnych * Funkcje obsługi kodu HTML Mimo że rysunki, dźwięki, animacje i aplety stają się coraz ważniejszą częścią sieci WWW, nadal bazuje ona na tekście. Podstawowym typem PHP przechowującym tekst jest typ string.
Ciągi w PHP Ciągi to sekwencje znaków traktowane jako odrębna jednostka. Mogą być przypisywane do zmiennych, używane jako parametry funkcji, zwracane z funkcji lub wysyłane na wyjście i oglądane w przeglądarce klienta. Najprostszą metodą stworzenia ciągu w PHP jest otoczenie znaków cudzysłowami (") bądź apostrofami ('): $ciag = 'Ciąg1; $inny_ciag = "Inny ciąg";
Różnica pomiędzy ciągami w cudzysłowach i apostrofach leży w interpretacji ich przez PHP. Jeżeli otoczysz ciąg apostrofami, prawie żadna interpretacja nie zostanie zastosowana, jeżeli zaś otoczysz cudzysłowami, PHP wklei wartości zmiennych w miejsce ich nazw i zamieni sekwencje sterujące na odpowiadające im znaki. Jeżeli np. wstawisz następujący kod do strony:
156_________________________________________Część l
powinieneś spodziewać się następującego wyniku: Czy musisz brać wszystko, co powiem, dosłownie? Czy musisz brać Swyrazenie dosłownie?\n
\ natrA lakffi
Szczegółowy opis traktowania ciągów z apostrofami i cudzysłowami znajduje się w części „String" w rozdziale 6.
Znaki i indeksy ciągu W przeciwieństwie do większości języków programowania, PHP nie posiada osobnego
typu znakowego. Zwykle funkcje, które w innych językach pobierają znak, w PHP spodziewają się ciągu o długości 1. Można uzyskać znak z ciągu, traktując ciąg jak tablicę z pierwszym indeksem równym 0. Uzyskany w ten sposób znak jest jednoliterowym ciągiem. Na przykład: $ciag - "Podwojony"; for (Sindex = O ; $index < 9; $index++ ) print("$ciag[$index]$ciąg t $index]") ;
daje w efekcie: PPooddwwooj joonnyy
Każda litera została wypisana dwa razy (liczba 9 wpisana jest w tym przykładzie dlatego, że nie wiemy jeszcze, jak określić długość ciągu — ponatrz r.a opis funkcji strlen () w części „Sprawdzanie ciągów").
Operatory dla ciągów PHP posiada tylko jeden prawdziwy operator dla ciągów: kropkę (.) — operator złączenia. Operator ten umieszczony pomiędzy ciągami tworzy nowy ciąg, będący ich sklejeniem. Na przykład: $zdanie_l = "Chciałbym podzielić się z wami ";
da w efekcie: Chciałbym podzielić się z wami moimi uwagami...
Zauważmy, że nie przekazujemy do instrukcji print wielu argumentów — przekazujemy jeden argument stworzony przez połączenie trzech ciągów. Pierwszy i drugi ciąg to zmienne, trzeci jest literałem.
Rozdział 9. » Ciągi i funkcje operujące na ciągach__________________________157
Operator złączenie nie jest tym samym co operator + w języku Java, nie przeciąża innego operatora. Jeżeli pomylisz się i dodasz dwa ciągi za pomocą +, zostaną zinterpretowane jako liczby. Na przykład jeden + dwa będzie równe O (ponieważ nie udało się przeprowadzić prawidłowej konwersji ciągów).
Złączenie i przypisanie PHP posiada operator skrócony (.=) który jest złączeniem z przypisaniem. Wyrażenie: $ciag .= $dodatek;
jest równoznaczne z: $ciag = Ściąg . Sdodatek;
Przy użyciu tego operatora nowy ciąg jest dodawany po prawej stronie starego. Jeżeli chcesz zmienić kolejność, musisz użyć dłuższej formy: $ciag = Sdodatek . Ściąg;
Funkcje operujące na ciągach PHP zawiera wiele funkcji działających na ciągach. Jeżeli zamierzasz napisać własną funkcję, która analizuje ciąg znak po znaku, aby stworzyć nowy ciąg, pomyśl, które z tych zadań będą często wykonywane. Jeżeli takie wystąpią, prawdopodobnie istnieje wbudowana funkcja realizująca tę czynność. W tej części zapoznamy się z podstawowymi funkcjami sprawdzającymi, porównującymi, modyfikującymi i drukującymi ciągi.
Dla programistów C. Powinniście znać wiele funkcji operujących na ciągach. Należy jedynie zapamiętać, że PHP zajmuje się przydziałem pamięci. Funkcje zwracające ciągi rezerwują pamięć na wynikowy ciąg i nie ma potrzeby wcześniej rezerwować pamięci.
Sprawdzanie ciągów Jakie pytania można zadać na temat ciągu? Na początek sprawdźmy przy użyciu funkcji strlen ( ) , ile znaków zawiera. Ściąg = "Ten ciąg zawiera 26 znaków"; print("To ma", strlen(Ściąg)."znaków");
Uruchomienie tego kodu daje następujący wynik: To ma 26 znaków
158_________________________________________Część l « Podstawy PHP
Odczytanie długości ciągu jest użyteczne w sytuacjach, gdy chcemy za pomocą pętli dostać się do wszystkich znaków ciągu. Bezużytecznym, ale pouczającym przykładem może być (używamy ciągu z poprzedniego przykładu): for (Sindex=0; $index
W przeglądarce pojawi się: Ten ciąg zawiera 26 znaków
Szukanie znaków i podciągów Następną kategorią pytań na temat ciągów może być pytanie o ich zawartość. Funkcja strpos ( ) szuka pozycji określonego znaku w ciągu, o ile w nim występuje. Stwister = "Król Karol kupił królowej Karolinie"; print("'k' występuje na pozycji", strpos($twister, 'k'). " ");
print("'q' występuje na pozycji", strpos(Stwister, 'q'). " ");
Wykonanie tego przykładu daje w efekcie: 'k' występuje na pozycji 11 'q1 występuje na pozycji
Pozycja litery 'q' pozostała niewypełniona, ponieważ funkcja strpos () zwraca FALSE w przypadku nieznalezienia znaku, a FALSE zostało skonwertowane do pustego ciągu. Funkcja strpos o jest jednym z przykładów, kiedy brak ścisłego określenia typów może stanowić problem. Jeżeli nie zostanie odnaleziona wartość, funkcja zwraca wartość FALSE. Jeżeli odnaleziony zostanie pierwszy znak ciągu, funkcja zwróci zero (ponieważ indeksowanie rozpoczyna się od zera). Jeżeli użyjemy tych wartości w wyrażeniu logicznym, obie zostaną zinterpretowane jako FALSE. Jedynym sposobem rozróżnienia tych wartości jest użycie operatora sprawdzającego identyczność obiektów (===, wprowadzony w PHP 4), który jest prawdziwy, jeżeli jego argumenty są identyczne i mają te same typy. Możesz go bezpiecznie użyć do porównania O z FALSE. Jeżeli używasz PHP 3, musisz sprawdzić typ zwracanej wartości, używając funkcji np. is_ integer ( ) .
Za pomocą funkcji strpos ( ) można również szukać ciągów, nie tylko pojedynczych znaków. Możesz także podać dodatkowy parametr numeryczny określający pozycję, od której funkcja ma rozpocząć szukanie. Możliwe jest też szukanie wstecz przy użyciu funkcji strrpos ( ) (dodatkowe 'r' pochodzi od słowa „reverse", czyli w tył). Funkcja ta pobiera ciąg do szukania oraz pojedynczy znak, którego szukamy. W przeciwieństwie do strpos ( ) , nie można podać podciągu do odszukania. Jeżeli użyjemy tej funkcji w naszym przykładowym zdaniu,
odszukamy inne wystąpienie litery k.:
Stwister = "Król Karol kupił królowej Karolinie"; print("'k' występuje na pozycji", strrpos(Stwister, 'k'). " ");
Rozdział 9. » Ciągi i funkcje operujące na ciągach________________________159
Czy ciągi są niezmienne?
W niektórych językach programowania (np. C) normalne jest manipulowanie ciągami przez ich bezpośrednią modyfikację, na przykład zapisywanie nowych znaków w środku ciągu. Inne języki (np. Java) trzymają programistów z daleka od takich operacji, tworząc klasę reprezentującą ciągi, które są niezmienne. Można utworzyć nowy ciąg tylko poprzez stworzenie zmodyfikowanej kopii ciągu. Po jego utworzeniu nie można bezpośrednio zmieniać jego znaków. W PHP ciągi mogą być zmieniane, ale w powszechnej praktyce jest traktowanie ciągów, jak gdyby były niezmienne. Można zmieniać ciąg, traktując go jako tablicę znaków i przypisywać bezpośrednio do tej tablicy: Ściąg = "abcdefg"; Sciag[5] = "X"; print (Ściąg . " ");
Daje to następujący wynik: abcdeXg
Taka operacja jest jednak nieudokumentowana i nie występuje nigdzie w podręczniku, chociaż analogiczne odczytywanie znaków jest zamieszczone. Prawie wszystkie funkcje operujące na ciągach zwracają zmienioną kopię ciągu, a nie przeprowadzają zmian na oryginale. Projektanci PHP preferują ten styl programowania. Radzimy nie modyfikować bezpośrednio ciągów, chyba że dzięki temu oszczędza się pamięć.
W tym przypadku odnajdziemy pierwsze 'k' w słowie „królowej": 'k' występuje na pozycji 17
Porównywanie i przeszukiwanie Często trzeba sprawdzać, czy dwa ciągi są identyczne. Szczególnie często w programach pracujących na danych wprowadzonych przez użytkownika. Najprostszą metodą porównania ciągów jest zastosowanie operatora równości (==), który porównuje zarówno liczby, jak i ciągi. Ciągi są takie same dla operatora ' = = ' , jeżeli zawierają dokładnie taką samą sekwencję znaków. Operator ten nie wykonuje żadnych dokładniejszych porównań (np. sprawdzenia obszarów pamięci).
Podstawową funkcją do porównywania ciągów jest strcmp ( ) . Posiada dwa ciągi jako argumenty, porównuje je znak po znaku aż do znalezienia różnicy. Funkcja zwraca wartość ujemną, jeżeli pierwszy ciąg jest „mniejszy" od drugiego, wartość dodatnią, gdy drugi ciąg jest mniejszy, oraz O, jeżeli ciągi są identyczne.
160
Część lI »» Podstawy Podstawy PHP PHP
Porównanie ciągów za pomocą operatora ' = = ' (a także < i >) jest prawidłowe tylko w przypadku, gdy oba argumenty są takimi ciągami, nie wykonano żadnej konwersji typów (więcej na ten temat w rozdziale 6.). Jedynie używając funkcji strcmpo otrzymujemy zawsze prawidłowe wyniki.
Funkcja strcasecmpO nie bierze pod uwagę wielkości liter podczas porównywania ciągów. Wywołanie funkcji: strcasecmp ( " h e j ! " , " H E J ! " ) powinno zwrócić 0.
Przeszukiwanie Funkcje porównujące ciągi sprawdzają, czy ciągi są identyczne. Aby sprawdzić, czy jeden ciąg zawiera się w drugim, używamy funkcji strpos () (opiszemy ją później) lub strstr () (ewentualnie jednej z jej odmian). Funkcja strstr () oczekuje w pierwszym parametrze ciągu do przeszukania, a w drugim ciągu do odszukania. Jeżeli operacja się powiedzie, funkcja zwróci fragment przeszukiwanego ciągu rozpoczynający się od pierwszego miejsca wystąpienia poszukiwanego fragmentu. Jeżeli nic nie zostanie odnalezione, zwracana jest wartość FALSE. W poniższym przykładzie zamieściliśmy jedno udane i jedno nieudane wywołanie funkcji. $ciag_do_przeszukania = "pierwszaoladrugaola"; Sciag_do_odszukania = "ola"; print("Wynik szukania ciągu Sciag_do_odszukania: " . strstr($ciag_do_przeszukania, Sciag_do_odszukania)); $ciag_do_odszukania = "ula"; print ("Wynik szukania ciągu Sciag__do_odszukania w " . strstr($ciag_do_przeszukania, $ciag_do_odszukania));
Wykonanie tego fragmentu da następujący wynik: Wynik szukania ciągu ola: oladrugaola Wynik szukania ciągu ula:
Puste miejsce za dwukropkiem w drugim wierszu wyniku jest wynikiem próby wydrukowania wartości FALSE, która została skonwertowana na pusty ciąg. Funkcja strstr () posiada alternatywną nazwę strchr (). Można używać dowolnej z nazw tej funkcji, wynik działania będzie identyczny. Podobnie jak strcmp (), strstr () posiada odmianę, która przy szukaniu ciągów identycznie traktuje małe i wielkie litery — stristr (). Funkcja ta działa identycznie jak strstr (), nie rozróżnia jednak wielkości liter. Dotychczas opisane funkcje operujące na ciągach zebraliśmy w tabeli 9.1.
Rozdział 9. » Ciągi i funkcje operujące na ciągach________________________161 Tabela 9.1.
Funkcje porównujące, przeszukujące i badające ciągi Funkcja
Opis
Strlen ( )
Zwraca długość ciągu podanego jako argument wywołania
Strpos ( )
Posiada dwa argumenty: ciąg do przeszukania i ciąg do znalezienia. Zwraca pozycję (licząc od zera) początku pierwszego miejsca wystąpienia ciągu lub wartość FALSE, jeżeli ciąg nie został odszukany. Można podać trzeci argument określający pozycję, od której rozpocząć szukanie
Strrpos ( )
Jak strpos ( ) , ale przeszukuje ciąg od tyłu. Poszukiwany ciąg może składać się tylko z jednej litery. Nie ma opcjonalnych argumentów
Strcmp ( )
Spodziewa się dwóch ciągów jako argumentów. Zwraca O, jeżeli ciągi te są identyczne.
Jeżeli funkcja znajdzie różnicę, zwraca wartość ujemną, jeżeli kod ASCII pierwszego różniącego się znaku jest mniejszy w pierwszym ciągu, lub wartość dodatnią, jeżeli mniejszy kod ASCII znajduje się w drugim ciągu
Strcasecmp ( )
Działa tak jak strcmp ( ) , traktując identycznie małe i wielkie litery
Strstr ()
Przeszukuje pierwszy ciąg, szukając w nim drugiego. Zwraca fragment pierwszego
Strchr ()
Działa tak samo jak strstr ()
Stristr ()
Działa tak samo jak strstr (), nie rozróżniając wielkości liter
ciągu rozpoczynający się od poszukiwanego fragmentu. Jeżeli nie ma drugiego ciągu w pierwszym, zwraca FALSE
Wycinanie podciągu Wiele z funkcji operujących na ciągach ma na celu wybranie określonego podciągu lub modyfikację go w ciągu oryginalnym. Warto wiedzieć, że większość funkcji modyfikujących ciąg nie zmienia oryginalnego ciągu, ale zwraca zmienioną kopię pozostawiając oryginał nietknięty. Podstawową metodą wycięcia fragmentu ciągu jest użycie funkcji substr ( ) , która zwraca ciąg będący określonym fragmentem ciągu przekazanego jako argument. Oprócz
ciągu, na którym operuje, funkcja wymaga podania liczby określającej początek wycinanego ciągu. Trzeci argument jest opcjonalny i określa długość wynikowego podciągu. Jeżeli nie zostanie on podany, funkcja zwraca fragment od podanej pozycji (za pomocą drugiego argumentu) do końca ciągu. Należy pamiętać, że pierwszy znak ciągu znajduje się na pozycji 0. Spójrzmy na następujący przykład: echo (substr("Wycinanie ciągów w PHP jest proste", 23));
Zwróci on w wyniku ,jest proste"; wyrażenie: echo (substr("Wycinanie ciągów w PHP jest proste", 10, 6));
wypisze słowo „ciągów" — sześcioznakowy ciąg rozpoczynający się od pozycji 10.
162_________________________________________Część l «
Podstawy PHP
Oba argumenty numeryczne, pozycja początkowa i długość mogą być ujemne. Jeżeli pozycja początkowa jest ujemna, oznacza to, że początek podciągu jest określany względem końca ciągu. Pozycja -l oznacza początek ciągu na ostatnim znaku, -2 na przedostatnim itd. Można oczekiwać, że podanie ujemnej długości zinterpretowane będzie analogicznie do pozycji początkowej i podciąg będzie określony odliczając wstecz od początkowego znaku ciągu. Nie jest to do końca prawdziwe. Znak określony przez indeks początkowy będzie pierwszym znakiem podciągu, a jego długość określona będzie odliczeniem podanej liczby znaków od końca ciągu. Spójrz na kilka przykładów, w których użyte zostały dodatnie i ujemne wartości: $alfabet = "abcdefghijklmnop"; print ("3:". substr( $alfabet, 3). " "); print ("-3:". substr( $alfabet, -3). " "); print ("3,5:". substrl $alfabet, 3, 5). " "); print ("3,-5:". substrl Salfabet, 3, -5). " "); print ("-3, -5:". substrl Salfabet, -3, -5). " "); print l"-3, 5:". substrl $alfabet, -3, 5). " ");
W wyniku otrzymujemy: 3: defghijklmnop -3: nop 3,5: defgh 3,-5: defghijk -3,-5: -3, 5: nop •*&
pJ^fejL jjggsjf •^-
W przykładzie z pozycją początkową -3 i długością -5 pozycja końcoznajduje się przed pozycją początkową, co jest sytuacją określaną jako „ciąg o ujemnej długości". W podręczniku, dostępnym pod adresem http://www.php.net/manual, jest napisane, że w takiej sytuacji funkcja substr o zwróci ciąg zawierający jeden znak znajdujący się na pozycji początkowej. Zamiast tego widzimy, że PHP 4.0.0 zwraca pusty ciąg. Należy szczególnie zwrócić uwagę na takie sytuacje. wa
Zauważmy, że pomiędzy funkcjami substr (), strstr () i strpos () występuje bli-
ski związek. Funkcja substr () wycina podciąg bazując na pozycji, strstr () wycina podciąg na podstawie zawartości a strpos () znajduje położenie podciągu. Jeżeli jesteśmy pewni, że $ciag zawiera $podciag, wtedy wyrażenie: s t r s t r ( $ c i a g , $podciag)
jest równoważne wyrażeniu: s u b s t r ( Ś c i ą g , strpos($ciag, p o d c i ą g ) )
Funkcje porządkujące Mimo że funkcje c h o p ( ) , l t r i m ( ) i t r i m ( ) są zwykłymi funkcjami wycinającymi podciąg, używa się ich do porządkowania ciągów. Funkcje te wycinają znaki odstępów z początku, końca lub początku i końca ciągu. A oto przykład:
Rozdział 9. » Ciągi i funkcje operujące na ciągach________________________163 Soryginal = " To przechodzi ludzkie pojęcie $f_chop = chop($oryginal); $f_ltrim = ltrim($oryginal); Sf_trim = trim($oryginal); print("Ciąg oryginalny: 'Soryginal' ");
";
print{"Długość ciągu:", strlen($oryginal). " ");
print("Po funkcji chop: '$f_chop' "); print("Długość ciągu:", strlen($f_chop). " "); print("Po funkcji Itrim: '$f_ltrim' "); print("Długość ciągu:", strlen($f_ltrim). " "1; print("Po funkcji trim: '$f_trim' "); print("Długość ciągu:", strlen($f_trim). " "};
W przeglądarce dostajemy:
Ciąg oryginalny: ' To przechodzi ludzkie pojęcie
'
Długość ciągu:33
Po funkcji chop: ' To przechodzi ludzkie pojęcie' Długość ciągu:30
Po funkcji Itrim: 'To przechodzi ludzkie pojęcie Długość ciągu:32
Po funkcji trim: 'To przechodzi ludzkie Długość ciągu:29
'
pojęcie1
Ciąg oryginalny ciąg ma na końcu trzy spacje (usuwane przez chop ( ) i trim ( ) ) oraz jedną na początku (usuwana przez Itrim ( ) i t r i m ( ) ) . Gdyby nazewnictwo funkcji było spójne, funkcja chop ( ) powinna nazywać się rtrim ( ) . Dokładniej opiszemy zawartość okna przeglądarki po wykonaniu tego fragmentu. Powtarzające się odstępy zostały przez przeglądarkę połączone w jeden. Jeżeli jednak zajrzysz do źródła strony, to na końcu ciągu nadal znajdują się trzy odstępy. Oprócz spacji funkcje te usuwają znaki zapisane jako sekwencje sterujące \n, \r, \t oraz \ O (znaki końca wiersza, tabulatory oraz znak końca ciągu używany w programach napisanych w C).
Mimo że nazwa funkcji chop ( ) (ang. rąbać) sugeruje destrukcyjne działanie, nie wpływa ona na ciąg przekazany jako argument. Po wykonaniu funkcji ciąg nie zmienia się.
Zastępowanie ciągów Funkcje operujące na ciągach, które omówiliśmy do tej pory, zwracały fragment ciągu przekazanego jako argument, zamiast tworzyć całkowicie nowy ciąg. Teraz zajmiemy się funkcjami str_replace ( ) i substr_replace ( ) .
Funkcja str_replace ( ) pozwala zamienić wszystkie miejsca wystąpienia podanego fragmentu ciągu na inny. Funkcja oczekuje trzech argumentów: ciągu do odszukania, ciągu, który zamieni szukany fragment oraz ciągu źródłowego. Na przykład: $pierwszy = "Birma jest nieco podobna do Rodezji.";
164_________________________________________Część l » Podstawy PHP
Wynikiem tych operacji jest zdanie: Panama jest nieco podobna do Zimbabwe.
Zastępowane są wszystkie miejsca wystąpienia podanego fragmentu. Jeżeli do ciągu PHP uda się wtłoczyć całą encyklopedię, można j ą będzie zaktualizować jednym wywołaniem.
Musisz zwrócić uwagę na sytuację, gdy wiele miejsca wystąpienia ciągu nachodzi na siebie. Fragment programu: $ciag = "ABA jest częścią ABABA"; Swynik = str_replace("ABA", "DBF", $ciag);
print("Wynik zamiany to '$wynik' "};
wyświetli ciąg: Wynik zamiany to 'DEF jest częścią DEFBA'
Jest to chyba najrozsądniejsze działanie.
Funkcja str_replace ( ) odszukuje fragmenty ciągu do wymiany, porównując ciąg źródłowy z fragmentem podanym jako parametr; funkcja substr_replace ( } zamienia fragment ciągu znajdujący się na określonej pozycji. Można ją wywołać maksymalnie z czterema argumentami: ciągiem, na którym wykonuje się operacja, ciągiem, który
jest wstawiany, początkową pozycją oraz parametrem opcjonalnym — długością fragmentu do wymiany. Na przykład: print(substr_replace("ABCDEFG",
"-",
2,
3);
daje w wyniku: AB-FG
Fragment CDE został zamieniony na pojedynczy znak minus. Możemy więc zastępować fragmenty ciągu ciągami o innej długości. Jeżeli nie zostanie podana długość fragmentu, wymieniony zostanie fragment ciągu od pozycji startowej do końca ciągu. Funkcja substr_replace ( ) pozwala również na używanie ujemnych wartości argumentów numerycznych. Są one traktowane identycznie jak ujemne wartości argumentów w funkcji substr ( ) ; opisaliśmy je w części „Wycinanie podciągu".
Mamy również kilka rzadziej używanych funkcji, które tworzą nowy ciąg na podstawie podanego jako parametr. Funkcja strrev () zwraca ciąg podany jako argument, ale pi-
sany wspak. Funkcja str_repeat ( ) tworzy ciąg zawierający ciąg źródłowy powtórzony daną liczbę razy. Przykładowo: print(str_repeat("witaj ", 3));
daje w wyniku: witaj witaj witaj
Funkcje przeszukujące i zamieniające ciąg zebrane zostały w tabeli 9.2.
Rozdział 9. » Ciągi i funkcje operujące na ciągach________________________165 Tabela 9.2. Funkcje przeszukujące i zamieniające ciąg
Funkcja
Działanie
substr ( )
Zwraca fragment ciągu opisany przez drugi argument, określający pozycję początkował opcjonalny trzeci argument, określający długość. Fragment rozpoczyna się na pozycji startowej i ma długość podaną w trzecim argumencie, a jeżeli nie został podany trzeci argument, obejmuje ciąg do końca. Ujemna
wartość pozycji startowej oznacza, że jest określana od końca ciągu, ujemny parametr określający długość powoduje, że koniec podciągu jest wyznaczany przez podaną liczbę znaków od końca ciągu
chop ( )
Zwraca ciąg podany jako argument bez końcowych znaków odstępu. Znakami odstępu są znaki " ", \n, \r, \t i \0
itrim ( )
Zwraca ciąg podany jako argument bez początkowych znaków odstępu
trim ( )
Zwraca ciąg podany jako argument bez początkowych i końcowych znaków odstępu
str_replace ( )
Zamienia podany fragment ciągu na inny. Funkcja ma trzy argumenty: ciąg do odszukania, ciąg, na który jest on zamieniany oraz ciąg bazowy. Zwraca kopię z zamienionymi na drugi argument wszystkimi miejscami wystąpienia pierwszego argumentu
substr_replace ( )
Wstawia fragment podany jako argument na pozycję określoną przez parametry numeryczne. Funkcja posiada cztery argumenty: ciąg bazowy, fragment wstawiany, pozycję początkową i liczbę znaków do wymiany. Zwraca kopię ciągu
podanego jako pierwszy argument, z ciągiem do zamiany wstawionym na określonej pozycji Jeżeli opuszczony zostanie czwarty argument, koniec ciągu zostanie zamieniony na fragment przekazany w argumencie. Ujemne wartości parametrów traktowane są identycznie jak w funkcji substr ( )
Ciągi i kolekcje znaków Oprócz poszukiwania podciągów, PHP oferuje kilka wyspecjalizowanych funkcji, które traktuj ą ciąg jako kolekcję, a niejako sekwencję znaków. Pierwsza z nich to funkcja strspn ( ) , za pomocą której można określić, jaka część ciągu składa się tylko ze znaków podanych jako argument. Przykładowo: $twister = "Król Karol kupił królowej Karolinie"; Sznaki = "Król kupił Karolinie"; print {"Fragment zawierający '$znaki' ma" . strspn($twister, $znaki). "znaki");
daje w wyniku: Fragment zawierający 'Król kupił Karolinie' ma 22 znaki
Pierwszym znakiem nieodnalezionym w ciągu $ znaki jest w „w" słowie „królowej".
166_________________________________________Część l
» Podstawy PHP
Funkcja strcspn ( ) działa bardzo podobnie, ale szuka znaków, które nie znajdują się w podanym ciągu. Na przykład wywołanie: echo (strcspn($twister, "abcd"));
spowoduje wypisanie liczby 6, ponieważ pierwszych sześć znaków ciągu nie zawiera znaków z ciągu „abcd". Na koniec przyjrzyjmy się fragmentowi, który wylicza statystykę liter (przykład korzysta z kilku nieopisanych jeszcze własności ciągów). $twister = "Król Karol kupił królowej Karolinie"; print ("Stwister "); $letter_array = count_chars(Stwister, 1); while ($cell = each($letter_array)) ( $letter = chr(Scell['key']);
Fragment ten daje w przeglądarce następujący wynik: Król Karol kupił królowej Karolinie
Znak: Znak: Znak:
K
Znak:
e
Znak: Znak : Znak: Znak:
a
Znak: Znak: Znak:
i j k 1 n o P r u w ł
Znak :
ó
Znak :
Znak: Znak : Znak:
liczba liczba liczba liczba liczba liczba liczba liczba liczba liczba liczba liczba liczba liczba liczba liczba
4 3
2 2
3 1
2 4 1 3 1 4 1 1 1
2
Funkcja count_chars ( ) zwraca w tablicy raport częstości występowania znaków w ciągu podanym jako argument. Kluczami tablicy są wartości kodu ASCII znaków, a wartością jest częstość występowania tych znaków w ciągu. Drugim argumentem funkcji jest liczba oznaczająca jeden z trybów działania funkcji. W trybie O zwracana jest tablica par klucz-wartość, w których kluczami są wszystkie wartości kodu ASCII od O do 255, a odpowiadającymi im wartościami — częstość występowania odpowiednich znaków. W trybach 1. i 2. w tablicy występują tylko znaki, które występują w ciągu (tryb 1.) lub nie występują w ciągu (tryb 2.). Tryby 3. i 4. zwracają ciąg, a nie tablicę. Ciąg ten zawiera wszystkie znaki występujące w źródłowym ciągu (tryb 3.) lub niewystępujące w nim (tryb 4.). Sposób odczytania danych z tablicy zwracanej przez funkcję count_ chars ( ) jest opisany w rozdziale 11. Funkcja chr ( ) użyta w poprzednim przykładzie jest opisana w rozdziale 6.
Rozdział 9. » Ciągi i funkcje operujące na ciągach__________________________167
Tabela 9.3.
Funkcje analizujące znaki zawarte w ciągu Funkcja
Opis
count_chars ( )
Wymaga ciągu znaków oraz liczby oznaczającej tryb pracy (od O do 4). Podaje raport częstości występowania znaków w ciągu, zwracając tablicę lub ciąg
strspn ( )
Wymaga dwóch ciągów. Zwraca długość początkowego fragmentu pierwszego ciągu, który można utworzyć z znaków zawartych w drugim ciągu
strcspn ( )
Wymaga dwóch ciągów. Zwraca długość początkowego fragmentu pierwszego ciągu, który można utworzyć ze znaków, których nie ma w drugim ciągu
Funkcje analizujące Czasami trzeba podzielić ciąg na fragmenty, biorąc pod uwagę różny sposób definiowania tych fragmentów. Proces podziału długiego ciągu na „słowa" jest zwany analizą, jest częścią interpretacji lub kompilacji zachodzącej przy pisaniu każdego programu, także PHP. PHP posiada funkcję, która realizuje taką operację — strtok ( ) . Funkcja strtok ( ) posiada dwa argumenty: ciąg przeznaczony do podziału oraz ciąg zawierający wszystkie znaki podziału (znaki występujące pomiędzy częściami). Podczas pierwszego wywołania używane są oba argumenty, a funkcja zwraca pierwszy fragment. Aby odczytać kolejne fragmenty, należy ponownie wywołać funkcję bez podawania ciągu. Ciąg jest zapamiętany jako ciąg bieżący, a funkcja zapamiętuje, w którym miejscu skończyła go analizować podczas poprzedniego wywołania. Rozpatrzmy następujący przykład: ?token = strtok( "klient-serwer CD-ROM baza danych", " "); while {Stoken) { print(Stoken. " ");
Stoken = strtok(" ");
.)
W wyniku działania tego fragmentu programu otrzymamy: klient-serwer CD-ROM
baza
danych
Początkowy ciąg został podzielony w miejscu każdej spacji. Zmieńmy teraz znak separatora: Stoken = strtok( "klient-serwer CD-ROM baza danych", "-"); while ($token) ( print(Stoken. " "); Stoken = s t r t o k ( " - " ) ;
}
Tak zmodyfikowany program da w wyniku:
168_________________________________________Część l » Podstawy PHP klient serwer CD
ROM baza danych
Możemy również podzielić ten ciąg we wszystkich tych miejscach, jednocześnie podając separator w postaci" -". Stoken = strtok( "klient-serwer CD-ROM baza danych", " -"); while ($token) ( print($token. " "); }
$token = s t r t o k t " -");
Ten program wypisze w oknie przeglądarki: klient serwer CD ROM
baza danych
Zauważ, że żaden z separatorów nie występuje w fragmentach wynikowych. Funkcja s t r t o k f ) zwraca kolejne fragmenty za następnymi wywołaniami. Możesz użyć funkcji explode ( ) , która działa podobnie, ale zapisuje w tablicy podzielony za jednym razem ciąg. Gdy fragmenty zostaną umieszczone w tablicy, możesz je na przykład posortować. Funkcja explode ( ) wymaga dwóch argumentów: ciągu separatora oraz ciągu do podzielenia. Zwraca ona tablicę zawierającą kolejne fragmenty ciągu. Przykład wywołania funkcji: $wynik = explode!",", "jeden, dwa, t r z y " ) ;
Tablica $wynik po wykonaniu tego wiersza programu będzie zawierał trzy elementy: "jeden", "dwa" i "trzy". Ciąg separatora w funkcji explode)) ma inne znaczenie niż w funkcji s t r t o k f ) . Wszystkie znaki separatora muszą wystąpić w ciągu źródłowym we właściwej kolejności, aby został on wykryty przez funkcję. Ciąg separatorów w funkcji s t r t o k f ) jest zbiorem pojedynczych znaków, z których każdy służy jako separator. Taka interpretacja separatora powoduje, że funkcja explode ( ) jest bardziej precyzyjna, ale i bardziej wymagająca. Jeżeli pozostawisz spację lub znak nowego wiersza, działanie funkcji może być inne, niż się spodziewałeś. Ponieważ cały separator jest usuwany podczas pracy explode ( ) , funkcja ta może być podstawą wielu ciekawych zastosowań. Poniższy przykład, przytaczany w dokumentacji PHP, dla wygody używa krótkich ciągów; należy pamiętać, że mogą mieć prawie dowolną długość. Funkcja explode ( ) jest szczególnie użyteczna w przypadku długich ciągów, kiedy analizowanie w inny sposób może być nużące. Policzymy miejsca wystąpienia podanego ciągu w pliku tekstowym dzięki wczytaniu pliku do ciągu i użyciu funkcji explode ( ) (w tym przykładzie użyliśmy kilku nieomówionych jeszcze funkcji, ale mamy nadzieję, że ich działanie będzie jasne).
Rozdział 9. » Ciągi i funkcje operujące na ciągach__________________________169
$filestring = fread($fd, filesize(Sfilename));
fclose(Sfd);
// Podzielimy na części, używając znacznika
jako separatora $pieces = explode("
, należy odjąć jeden // od liczby fragmentów echo ($num_pieces -l );
?>
Istnieje funkcja odwrotna do explode ( ) — implode ( ) , która wymaga dwóch argumentów: ciągu „sklejającego" (analogicznie do ciągu separatora w explode ( ) ) oraz tablicy ciągów podobnej do tej zwracanej przez explode ( ) . Zwraca ona ciąg stworzony poprzez wstawienie ciągu sklejającego pomiędzy kolejne elementy z tablicy.
Użyjemy tych dwóch funkcji, aby wymienić wszystkie miejsca wystąpienia jakiegoś ciągu w pliku tekstowym. Należy pamiętać, że separator jest usuwany przez funkcję explode ( ) , jeżeli chcesz, aby występował w pliku wynikowym, trzeba zamienić go ręcznie. W kolejnym przykładzie zmienimy znaczniki czcionki na stronie WWW.
$fd = fopen($filename, "r"); Sfilestring = fread($fd, filesize(Sfilename)); fclose($fd); Sparts = explode("arial, sans-serif", Sfilestring); Swhole = implode("arial, verdana, sans-serif", Sparts); // Zapisujemy na nowo plik $fd = fopen(Sfilename, "w"); fwrite(Sfd, Swhole); fclose(Sfd); ?>
Funkcje zmiany wielkości liter Funkcje poniższe zmieniają wielkość liter z małych na wielkie, i odwrotnie. Pierwsze dwie operują na całym ciągu, kolejne — tylko na pierwszych literach.
strtolowerO Funkcja strtolower ( ) zwraca ciąg ze wszystkimi małymi literami. Nie ma znaczenia, czy na początku cały ciąg był zapisany wielkimi literami, czy wielkie i małe były wymieszane.
echo Smalę; ?>
Ten fragment programu zwróci ciąg: "on nie wie, że krzyczy".
170_________________________________________Część l
»
Podstawy PHP
strtoupper() Funkcja strtoupper ( ) zwraca ciąg z wszystkimi wielkimi literami. Nie ma znaczenia, czy na początku cały ciąg był zapisany małymi literami, czy wielkie i małe były wymieszane.
Soryginalny = "napisz to wyraźnie";
echo("".strtoupper($oryginalny).""); ?>
ucfirst() Funkcja ucf irst () zmienia pierwszą literę ciągu na wielką.
Soryginalny = "przykładowe zdanie."; echo(ucfirst(Soryginalny)}; ?>
ucwordsQ Funkcja ucwords ( ) zamienia pierwsze litery wyrazów w ciągu na wielkie.
^^\ ^-A
Zarówno ucwords o, jak i ucf irst o nie konwertują liter na małe. Zmieniają tylko właściwe początkowe litery na wielkie. Jeżeli w środku ciągu wystąpią wielkie litery, nie zostaną zamienione.
Funkcje znaków sterujących PHP działa jako język łączący strony WWW z bazami danych, serwerami LDAP, połączeniami poprzez gniazda sieciowe czy protokół HTTP. Zwykle dialog taki jest realizowany dwuetapowo. Najpierw tworzony jest ciąg komunikatu (na przykład zapytanie do bazy danych), następnie jest wysyłany do programu, z którym realizowana jest komunikacja. Często program ten w specjalny sposób interpretuje niektóre znaki. Aby były one potraktowane jako część literału, a nie kod sterujący, należy je specjalnie oznaczyć.
Wielu użytkowników uaktywnia opcję magic-quotes. Istnieją też funkcje usuwające i dodające znaki \. Dodawanie i usuwanie znaków backslash jest użyteczne również w innym przypadku: podczas obróbki formularzy HTML za pomocą zmiennych PHP. Mogą one zawierać wiele apostrofów, które są częścią HTML i nie powinny być interpretowane przez PHP. Jeżeli masz wiele takich fragmentów, możesz przyspieszyć pracę, używając funkcji zamiast ręcznego dodawania znaków sterujących.
Rozdział 9. » Ciągi i funkcje operujące na ciągach________________________171
Funkcja addslashes ( ) oznacza apostrofy, cudzysłowy, znaki backslash oraz znaki NULL za pomocą znaku backslash. Zwykle jest to konieczne przy wysyłaniu znaków do bazy danych.
$escapedstring = addslashes("He said, 'I'm a dog."); Squery = "INSERT INTO test (quote) values ('Sescapedstring')"; $result = mysql_query($query) or die(mysql_error()); ?>
Zabezpiecza to przed potraktowaniem apostrofu przed "I" jak zakończenie wyrażenia przez serwer SQL. Jeżeli odczytujesz dane z bazy, musisz użyć funkcji stripslashes ( ) , aby usunąć znaki sterujące.
Sresult = mysql_query($query) or die (mysql_error{)); $new_row = mysql_fetch_array{$result) ; Squote = stripslashes($new_row[0]); echo Squote; ?>
Funkcja quotemeta ( ) przetwarza wszystkie znaki specjalnego znaczenia w poleceniach powłoki Unix: . \ + * ? [ A ] ( $ ) . Na przykład: $literal= 'Znaki ($, *) maja dla mnie szczególne znaczenie \n '; $qm = quotemeta($literal};
echo $qm;
Wykonanie tego fragmentu da w wyniku: Znaki \(\$, \*\) maja dla mnie szczególne znaczenie \\n
Funkcje sterujące specyficzne dla HTML opisano na końcu tego rozdziału.
Formatowanie danych Podstawowymi konstrukcjami używanymi do drukowania danych są print i echo, które zostały opisane w rozdziale 5. Zwykle wartości zmiennych są wypisywane poprzez wbudowywanie zmiennych w ciągi otoczone cudzysłowami (i są zamieniane na
wartości) i przekazywanie takiego ciągu do instrukcji echo lub print.
Jeżeli potrzebujesz dokładniej sformatowanego tekstu, PHP udostępnia funkcje print f () i sprintf (), które działają analogiczne do funkcji o tych samych nazwach w C. Obie
funkcje mają takie same argumenty: specjalny ciąg formatujący (opiszemy poniżej), a następnie dowolną liczbę argumentów, które zostaną wklejone we właściwe miejsca ciągu formatującego. Jedyną różnicą pomiędzy printf ( ) i sprintf ( ) jest to, że printf ( ) wysyła wynik bezpośrednio na wyjście, a sprintf ( ) zwraca wynik jako ciąg.
172_________________________________________Część l
*
Podstawy PHP
Dla programistów C: funkcja sprintf o różni się od jej wersji z C jeszcze jednym szczegółem. W C należy utworzyć ciąg wynikowy, PHP sam utworzy ten ciąg.
Najbardziej skomplikowaną częścią tych funkcji jest ciąg formatujący. Każdy znak, jaki umieścisz w tym ciągu, pojawi się w ciągu wynikowym, oprócz sekwencji znaków rozpoczynających się od %. Znak % oznacza początek „specyfikacji konwersji", która wskazuje sposób wydruku argumentu odpowiadającego tej specyfikacji. Po znaku % można umieścić pięć elementów określających sposób konwersji (niektóre opcjonalnie): wypełnienie, wyrównanie, minimalna szerokość, dokładność oraz typ. 1. Pojedynczy (opcjonalny) znak wypełnienia może być zerem lub spacją. Znak
ten jest używany do wypełniania nieużywanego miejsca, które zarezerwowano, określając minimalną szerokość. Jeżeli znak ten nie zostanie podany, wolne miejsce zostanie wypełnione spacjami.
2. Opcjonalny znak wyrównania „-". Jeżeli został umieszczony, wartość jest wyrównana do lewej strony; jeżeli go nie ma, wartość jest wyrównana do prawej strony.
3. Opcjonalna liczba określająca minimalną szerokość; wartość zajmuje co najmniej tyle miejsca. Jeżeli będzie potrzebne więcej miejsca do wydrukowania
wartości, przekroczona zostanie szerokość pola.
4. Opcjonalne określenie szerokości części ułamkowej. Składa się z kropki i liczby określającej dokładność drukowania liczb rzeczywistych (dla innych wartości nie ma znaczenia). 5. Pojedynczy znak określający sposób, w jaki ma być interpretowany typ zmiennej. Znak f oznacza drukowanie liczby rzeczywistej, s oznacza drukowanie ciągu, reszta znaków (b, c, d, o, x, x) oznacza, że wartość jest traktowana jak liczba całkowita i drukowana w różnych formatach. Formaty te to: format binarny dla litery b, c oznacza drukowanie znaku o odpowiednim kodzie ASCII, o oznacza liczbę oktalną, x to liczba heksagonalna (pisana małymi literami), a x to liczba heksagonalna z wielkimi literami. Przykładem może być drukowanie tej samej liczby rzeczywistej na różne sposoby:
?>
Wynik działania tego fragmentu: 3.141590,
3.141590, 3.141590000000000,
3.14
Konstrukcja w HTML wskazuje przeglądarce, aby nie formatowała tak oznaczonego bloku (nie usuwała wielokrotnych odstępów itp.).
Rozdział 9. » Ciągi i funkcje operujące na ciągach__________________________173
Zaawansowane własności ciągów Omówiliśmy już większość podstawowych operacji na ciągach: tworzenie, dzielenie, porównywanie, szukanie podciągów i drukowanie. Teraz przedstawimy kilka zaawansowanych funkcji.
Wyrażenia regularne Pełny opis wyrażeń regularnych wykracza poza ramy tego rozdziału. W zamian pokażemy, do czego mogą się one przydać. Podamy też kilka przykładów ich użycia.
Dlaczego używamy wyrażeń regularnych? Porównywanie ciągów i szukanie podciągów, które opisaliśmy wcześniej, działa świetnie, ale jest ograniczone do literałów. Załóżmy, że chcesz skontrolować, czy ciąg jest szczególnym rodzajem adresu WWW: rozpoczyna się www. a kończy się .com, a pomiędzy nimi jest jeden wyraz pisany małymi literami. Przykładowo te ciągi są akceptowane: www. ibm. com www.zend.com
Te ciągi powinny być odrzucone: Java.sun.com www.j ava.sun.com
www.php.net www.IBM.com www.adresy nie mogą mieć spacji.com
Po krótkim przemyśleniu staje się jasne, że nie ma wygodnego sposobu na użycie porównania ciągów i wycinania podciągów do stworzenia odpowiedniego testu. Możemy sprawdzić, czy istnieje www. oraz .com, ale trudno sprawdzić to, co jest w środku. Do tego świetnie nadają się wyrażenia regularne.
Wyrażenia regularne w PHP Wyrażenia regularne są sposobem porównywania ciągów ze znakami specjalnymi, które zastępuj ą większe porcje ciągu docelowego. Istniajądwie klasy wyrażeń regularnych, z którymi PHP może działać: wyrażenia w stylu POSIX i wyrażenia zgodne z Perl (w tej książce nie będziemy zajmować się wyrażeniami zgodnymi z Perl). Uproszczone zasady wyrażeń regularnych w stylu POSIX są następujące: * Znaki, które nie są znakami specjalnymi, są porównywane dosłownie. Przykładowo litera we wzorcu jest porównywana z literą w ciągu. A
* Znak specjalny oznacza tylko początek ciągu, znak $ oznacza tylko koniec ciągu.
* Znak specjalny . oznacza dowolny znak. Znak specjalny * oznacza O lub więcej miejsc wystąpienia poprzedniego wyrażenia regularnego, a znak + oznacza jedno lub więcej miejsc wystąpienia poprzedniego wyrażenia.
174_________________________________________Część l « Podstawy PHP
* Zestaw znaków otoczony nawiasami kwadratowymi zastępuje dowolny z tych znaków — [ab] zastępuje zarówno a, jak i b. Można również podać zakres znaków w nawiasach, używając kreski — [a-c] zastępuje a, b lub c. * Znaki specjalne poprzedzone znakiem \ tracą specjalne znaczenie i są porównywane dosłownie. Przy użyciu tych zasad stworzyliśmy wyrażenie, które pasuje do interesujących nas adresów WWW: "www\.[a-z]+\.com$
Na początku tego wyrażenia mamy znak A, który wskazuje, że na początku ciągu powinny znajdować się znaki www. Następnie znajduje się kropka poprzedzona znakiem backslash, który wskazuje, że w tym miejscu naprawdę powinna być kropka, a nie specjalny znak zastępujący dowolny znak w porównywanym ciągu. Kolejnym fragmentem wyrażenia jest otoczony nawiasami kwadratowymi zakres liter, obejmujący wszystkie małe litery. Co najmniej jedna z tych liter musi wystąpić tutaj jeden lub więcej razy. Na koniec w ciągu musi wystąpić fragment .com. Znak specjalny $ wskazuje, że .com kończy ciąg. Tak skonstruowanego wyrażenia użyjemy jako argumentu funkcji ereg ( ) , która wymaga ciągu zawierającego wyrażenie regularne oraz ciągu z nim porównywanego jako argument. Napiszmy funkcję sprawdzającą, przy użyciu funkcji ereg ( ) , interesujące
nas adresy WWW.
function simple_dot_com(Surl) ( return (ereg('"www\.[a-z]+\.com$', $url)); )
Funkcja ta zwraca TRUE lub FALSE w zależności od tego, czy udało jej się porównanie z naszym wzorcem. Użyjmy tej funkcji do weryfikacji kilku wymienionych wcześniej adresów (program przegląda tablicę w sposób, który dokładnie opiszemy w następnym
'java.sun.com', 'www.php.net', 'www.IBM.com', 'www.adresy WWW nie mają odstępów.com');
while ($test = array_pop($urls_to_test)) (
if (simple_dot_com($test)) print ("\"$test\"jest prostym adresem ,com "); else print ("\"$test\"NIE jest prostym adresem .com ");
}
Wynikiem działania tego programu jest: "www.adresy WWW nie mają odstepow.com" NIE jest prostym adresem .com "www.TBM.com" NIE jest prostym adresem .com "www.php.net" NIE jest prostym adresem .com "java.sun.com" NIE jest prostym adresem .com "www.zend.com" jest prostym adresem .com "www.java.sun.com" NIE jest prostym adresem .com "www.ibm.com" jest prostym adresem .com
O takie właśnie rozdzielenie nam chodziło.
Rozdział 9. » Ciągi i funkcje operujące na ciągach__________________________175
W wielu komputerach działających pod Unixem wpisanie "mań 7 regex" wyświetli podręcznik na temat wyrażeń regularnych POSIX. Jeżeli nie, wpisz "man regex" i sprawdź, na której stronie znajdują się interesujące cię informacje.
Funkcje korzystające z wyrażeń regularnych Funkcje korzystające z wyrażeń regularnych zebrane są w tabeli 9.4. Tabela 9.4.
Funkcje korzystające z wyrażeń regularnych Funkcja
Opis
ereg ( )
Wymaga dwóch argumentów i opcjonalnie trzeciego. Pierwszy ciąg jest wyrażeniem regularnym w stylu POSIX, drugi jest porównywanym ciągiem. Funkcja zwraca TRUE, jeżeli porównanie się powiodło. Jeżeli porównanie nie udało się, zwraca FALSE. Jeżeli w trzecim argumencie zostanie podana tablica, a fragmenty wzorca
są otoczone nawiasami, części porównywanego ciągu, które pasują do kolejnych fragmentów w nawiasach, są kopiowane do kolejnych komórek tablicy ereg_replace ( )
Wymaga trzech argumentów: wyrażenia regularnego w stylu POSIX, ciągu, który jest wstawiany, oraz ciągu, na którym przeprowadzane jest wstawianie. Funkcja przegląda ciąg podany jako trzeci argument i zamienia fragmenty pasujące do wzorca ciągiem podanym jako drugi argument. Zwracany jest zmodyfikowany ciąg Jeżeli we wzorcu wy stępuj ą części otoczone nawiasami (jak w ereg ( ) ) , ciąg wstawiany może zawierać specjalny fragment '\\cyfra' (dwa znaki backslash
i pojedyncza cyfra), zamieniany na odpowiedni fragment ciągu wynikowego
eregi < >
Funkcja działa identycznie jak ereg ( ) , ale litery w wyrażeniu regularnym są porównywane niezależnie od wielkości
eregi_replace ( )
Funkcja działa identycznie jak ereg^replace ( ) , ale litery w wyrażeniu
split ()
regularnym są porównywane niezależnie wielkości
Wymaga wzorca, ciągu źródłowego i opcjonalnego limitu fragmentów. Zwraca tablicę ciągów utworzonych przez podział ciągu źródłowego na fragmenty,
rozdzielone fragmentami pasującymi do wyrażenia regularnego. Jest to funkcja analogiczna do explode ( ) poza tym, że separator nie jest literałem, ale wyrażeniem regularnym
Jeżeli korzystasz z funkcji korzystających z wyrażeń regularnych z wzorcem pozbawionym znaków specjalnych, prawdopodobnie używasz kosztownego narzędzia w miejscu, gdzie wystarczy mniej skomplikowane. Jeżeli próbujesz porównywać prosty ciąg z prostym ciągiem, powinieneś użyć jednej z prostszych i szybszych funkcji, które opisaliśmy wcześniej w tym rozdziale.
176_________________________________________Część l
«
Podstawy PHP
Funkcje HTML Na koniec przedstawimy kilka funkcji manipulujących ciągami, które są specyficzne dla pracy ze stronami WWW. Tabela 9.5. Funkcje specyficzne dla pracy ze stronami WWW
Funkcja
Opis
html special char s ()
Pobiera jako argument ciąg i zwraca ciąg z zamienionymi czterema znakami, które mają specjalne znaczenie w kodzie HTML. Każdy z tych znaków jest zamieniony na odpowiadającą mu jednostkę HTML, która wygląda w przeglądarce identycznie jak oryginał. Znak & jest zamieniany na &,
"" (cudzysłów) jest zamieniany na ", < zamieniany jest na < a > na > htmlentities ( )
Zamienia wszystkie znaki posiadające jednostki HTML na te jednostki
ge t_html_
Wymaga jednej z dwóch starych (HTML_SPECI AL_CHARS,
translation_table ()
HTML_ENTITIES) i zwraca tablicę konwersji, używaną przez funkcje
htmlspecialcharsO i htmlentities(). Kluczami tablicy konwersji są znaki, a wartościami ich zamienniki n!2br ( )
Wymaga ciągu jako argumentu. Zwraca ciąg z zamienionymi wszystkimi
miejscami wystąpienia \n na . Pomaga przy obliczaniu długości akapitów wyświetlanych później w przeglądarce
strip_tags ()
Pobiera jako argument ciąg i zwraca ten ciąg usuwając znaczniki HTML i PHP
Podsumowanie Ciągi są sekwencjami znaków. Jest to jeden z sześciu podstawowych typów danych
w PHP. W przeciwieństwie do niektórych innych języków, nie ma tu osobnego typu znakowego, pojedynczy znak zachowuje się jak ciąg o długości l. Ciągi w kodzie są
otaczane apostrofami (') lub cudzysłowami ("). Ciągi otoczone apostrofami są interpretowane prawie dosłownie, a ciągi otoczone cudzysłowami interpretują kilka sekwencji sterujących i automatycznie wstawiaj ą wartości zmiennych.
Podstawowym operatorem ciągów jest ' . ', który łączy dwa ciągi. Istnieje dodatkowo spora gama funkcji, które umożliwiają sprawdzanie, porównywanie, szukanie, wycinanie, zamianę zawartości ciągu. PHP udostępnia także wyrażenia regularne, zgodne ze standardem POSIX i Perl, do zaawansowanych zastosowań.
Rozdział 10.
Matematyka W tym rozdziale: * Podstawowe typy numeryczne i operacje arytmetyczne ** Funkcje wykładnicze, trygonometryczne i funkcje konwersji podstawy * Generowanie liczb losowych * Arytmetyka o dowolnej dokładności Jeżeli chcesz wykonywać poważne obliczenia naukowe lub statystyczne, języki skryptowe nie są do tego odpowiednim narzędziem. Mimo tego PHP zawiera szeroką gamę funkcji, które zapewniają wykonanie większości zadań matematycznych. Zapewnia arytmetykę o dowolnej dokładności czy dostęp do bibliotek funkcji mieszających i kryptograficznych. Projektanci PHP nie próbowali dodawać nowości w tej dziedzinie. Wiele z podstawowych funkcji matematycznych w PHP to proste odpowiedniki analogicznych funkcji w C (więcej na ten temat w przypisie „Rzut oka za kurtynę" poniżej).
Typy numeryczne PHP posiada tylko dwa typy numeryczne: integer (znany również jako long) oraz
double (float), które odpowiadają największym typom numerycznym w C. PHP automatycznie konwertuje typy numeryczne, mogą więc być bezpiecznie mieszane w wyrażeniach arytmetycznych; zwykle dają prawidłowy wynik. PHP potrafi również w razie potrzeby skonwertować ciąg na liczbę.
Jeżeli chcesz, aby wartość została zinterpretowana jako wartość określonego typu numerycznego, skorzystaj z rzutowania typu, poprzedzając zmienną nazwą typu w nawiasach: (double) $zmierma (integer) Szmienna
178_________________________________________Część l »
Podstawy PHP
Możesz również użyć funkcji intval () i doubleval (), które skonwertują argument wywołania na odpowiedni typ numeryczny. Dokładny opis typów integer i double znajduje się w rozdziale 6.
Operatory matematyczne Większość operacji matematycznych w PHP jest realizowana przez wywołania funkcji,
a nie przy użyciu operatorów. Oprócz operatorów porównania, opisanych w rozdziale 7.,
PHP zawiera pięć operatorów realizujących proste działania oraz kilka operatorów „skrótowych", pozwalających na bardziej zwięzłe przypisywanie i zwiększanie wartości.
Operatory arytmetyczne Pięć operatorów dostępnych w PHP to cztery operatory dostępne w prostym czterodziałaniowym kalkulatorze oraz operator dzielenia modulo (%). Operatory te zostały opisane w tabeli 10.1. Tabela 10.1.
Operatory arytmetyczne Operator
Opis
+
Suma dwóch argumentów
-
Jeżeli występują dwa argumenty, argument po prawej stronie jest
odejmowany od argumentu stojącego po lewej stronie. Jeżeli występuje tylko argument po prawej stronie, zwracana jest jego wartość
Przykład
4 + 9.5 = 13.5 50 - 75 = -25
- 3.9 = -3.9
o przeciwnym znaku
*
Iloczyn dwóch argumentów
3 . 1 4 * 2 = 6.28
/
Dzielenie zmiennoprzecinkowe argumentu po lewej stronie przez argument po prawej stronie
5 / 2 = 2.5
%
Całkowita reszta z dzielenia argumentu po lewej stronie przez argument
po prawej stronie
101 % 50 = l
999 % 3 = O
43 % 94 = 43
-12% 10 = -2 -12%-10 = -2
Operatory arytmetyczne i typy W przypadku pierwszych trzech operatorów: +, -, * nastąpi konwersja do typu double na argumentach typu integer. Jeżeli oba argumenty są typu integer, wynik również
będzie tego typu. Jeżeli jeden z argumentów będzie typu double, wynik również będzie typu double. W przypadku dzielenia nastąpi też zmiana typu na double, jeżeli argumenty nie dzielą się bez reszty przez siebie. ,^-vZ, lrjJ3\
Jeżeli potrzebujesz wyniku dzielenia całkowitego zamiast zmiennoprzecinkowego, trzeba skonwertować wynik do typu integer. Na przykład intvai(5/2j daje w wyniku liczbę całkowitą 2.
Operator modulo Arytmetyka modulo jest czasami nazywana w szkole „arytmetyką zegara". Proces dzielenia modulo przez liczbę jest podobny do „owijania" pierwszego argumentu dookoła drugiego. Wynik tej operacji jest zawsze mniejszy od drugiego argumentu. Można to porównać do zwykłego zegara analogowego, który pokazuje czas modulo 12, natomiast „wojskowe" zegary pokazują czas modulo 24 (nie jest to dokładnie to samo, ponieważ dzielenie modulo daje wynik od O do n-1, a nie od l do n). Operator modulo w PHP (%) oczekuje argumentu typu integer i jeżeli otrzyma wartość double, najpierw konwertuje ją do typu integer, odrzucając część ułamkową. Wynikiem działania jest zawsze liczba całkowita. Większość języków programowania posiada operator modulo. Zwykle różnią się obsługą ujemnych argumentów. W niektórych językach wynik działania jest zawsze dodatni i-2 % 26 jest równe 24. W PHP-2 % 26 wynosi -2, a wyrażenie $mod = $first % $ second jest równoważne wyrażeniu: if ($first >=0) $rood = $first % abs(Ssecond); else $mod = -(abs(Sfirst) % abs(Ssecond));
Funkcja abs ( ) zwraca wartość bezwzględną argumentu.
Operator inkrementacji PHP korzysta z większości składni C, a wiadomo, że programiści C są dumni ze zwięzłości. Zapożyczone z C operatory inkrementacji i dekrementacji pozwalają na zwięzły zapis konstrukcji $count=$count+l, które wy stępuj ą bardzo często. Operator inkrementacji (++) dodaje jeden do zmiennej, operator dekrementacji odejmuje jeden od zmiennej. Oba te operatory występują w dwóch postaciach: „przyrostkowej" — umieszczanej po zmiennej, oraz „przedrostkowej" — umieszczanej przed zmienną. Oba mają to samo działanie, ale chociaż w różny sposób obliczają wartość wyrażeń. Operator przyrostkowy zmienia wartość zmiennej po zwróceniu przez nią wartości, przedrostkowy zmienia jej wartość i zwraca nową. Możesz prześledzić różnice, używając tych operatorów w przypisaniach podobnych do poniższych:
Operacje te dają w wyniku: Przyrostkowy + +: count wynosi: l, result wynosi: O Przedrostkowy ++: count wynosi: l, result wynosi: l Przyrostkowy —: count wynosi: -l, result wynosi: O Przedrostkowy —: count wynosi: -l, result wynosi: -l
Operator przypisania Operator inkrementacji ++ pozwala uniknąć pisania przy operacji dodawania jeden do zmiennej. Nie pomoże, jeżeli chcemy dodać dowolną inną liczbę lub wykonać inną operację arytmetyczną. Na szczęście wszystkie operatory arytmetyczne posiadają odpowiednie operatory przypisania (+=, -=, *=, /= i %=), które przypisują zmiennej wynik operacji arytmetycznej na niej samej. Wyrażenie następujące: Scount = Scount * 3;
może zostać skrócone do: Scount *= 3;
natomiast wyrażenie: Scount = Scount + 17;
odpowiada operacji: Scount += 17;
Operatory porównania PHP zawiera zwykle arytmetyczne operatory porównania, które wymagają prostych wartości (liczb lub ciągów) jako argumentów; zwracaj ą wartość TRUE bądź FALSE:
* Operator < (mniejszy niż) zwraca wartość TRUE, jeżeli wartość po lewej stronie jest mniejsza od wartości po prawej stronie. W przeciwnym przypadku zwraca FALSE.
** Operator <= (mniejszy lub równy) zwraca wartość TRUE, jeżeli wartość po lewej stronie jest mniejsza bądź równa wartości po prawej stronie. W przeciw-
nym przypadku zwraca FALSE.
* Operator > (większy niż) zwraca wartość TRUE, jeżeli wartość po lewej stronie jest większa od wartości po prawej stronie. W przeciwnym przypadku zwraca FALSE.
* Operator >= (większy lub równy) zwraca wartość TRUE, jeżeli wartość po lewej stronie jest większa lub równa od wartości po prawej stronie. W przeciwnym przypadku zwraca FALSE. * Operator == (równy) zwraca wartość TRUE, jeżeli argumenty są sobie równe. W przeciwnym przypadku zwraca FALSE. * Operator ! = (różny) zwraca wartość FALSE, jeżeli argumenty są sobie równe. W przeciwnym przypadku zwraca TRUE.
+ Operator === (identyczny) zwraca wartość TRUE, jeżeli argumenty są sobie równe i są tego samego typu. W przeciwnym przypadku zwraca FALSE. Przykłady użycia operatorów porównania oraz niektóre pułapki występujące podczas porównywania liczb double oraz ciągów opisane zostały w rozdziale 7. Operator „identyczny" (===) jest nowością w PHP 4. Jest istotny z powodu automatycznej konwersji typów wykonywanej przez PHP. Żadne z poniższych wyrażeń nie ma wartości TRUE: 2 ==- 2.0 2 === "2" "2.0" === 2.0 O === FALSE
Nieoceniony, jeżeli mamy funkcję, która zwraca ciąg w przypadku prawidłowego wykonania, a wartość FALSE, gdy nie uda się. Porównywanie zwracanej wartości może być mylące, ponieważ FALSE jest traktowane identycznie jak pusty ciąg; operator identyczności rozróżnia te wartości.
Kolejność operacji i nawiasy Zasady kolejności wykonywania operacji decydują, który operator w wyrażeniu pierwszy pobierze otaczające je argumenty. Kompletną tabelę kolejności operatorów można znaleźć w podręczniku dostępnym pod adresem http://www.php.net. Poniżej przedstawiamy najważniejsze zasady kolejności dla arytmetyki:
182_________________________________________Część l
»
Podstawy PH
* Operatory arytmetyczne mają wyższy priorytet od operatorów porównania. * Operatory porównania mają wyższy priorytet od operatorów przypisania.
* Operatory *, / i % maj ą ten sam priorytet. * Operatory + i - mają ten sam priorytet. * Operatory *, / i % mają wyższy priorytet od + i -. * Jeżeli operatory mają ten sam priorytet, działania wykonywane są od lewej do prawej. Jeżeli uważasz, że priorytety operatorów są trudne do zapamiętania, używaj nawiasov Dla przykładu, czy możesz szybko określić wartość tego wyrażenia? l + 2 * 3 - < 5 - 5 / 4 % 3
Okazuje się, że wartością tego wyrażenia jest 2. Dużo łatwiej to stwierdzić, jeżeli di damy nawiasy (prawdę mówiąc, niepotrzebne). ( (l + (2 * 3) - 4) - ( (5 / 4) % 3)
Proste funkcje matematyczne Następnym krokiem w kierunku bardziej skomplikowanych zagadnień są funkcje real żujące konwersje między dwoma typami numerycznymi (opisane w rozdziale 6.) on zwracające minimum i maksimum ze zbioru liczb (zebrane w tabeli 10.2). Tabela 10.2. Proste funkcje matematyczne Funkcja
Opis
floor ( )
Wymaga jednego argumentu (zwykle rzeczywistego) i zwraca największą liczbę całkowitą, mniejszą lub równą argumentowi
cel l ( )
Wymaga jednego argumentu (zwykle rzeczywistego) i zwraca najmniejszą liczbę całkowitą, większą lub równą argumentowi Wymaga jednego argumentu (zwykle rzeczywistego) i zwraca najbliższą liczbę całkowitą. Jeżeli część ułamkowa wynosi 0,5, zwracana jest najbliższa liczba parzysta Wartość bezwzględna. Jeżeli argument jest ujemny, zwraca odpowiadającą mu wartość dodatnią. Jeżeli argument jest dodatni, zwraca argument Pobiera dowolną liczbę argumentów numerycznych (ale co najmniej jeden) i zwraca najmniejszy z nich Pobiera dowolną liczbę argumentów numerycznych (ale co najmniej jeden) i zwraca największy z nich
round ( ) abs ( ) m
in ( )
max ( )
Wynikiem poniższego wyrażenia jest 3, ponieważ wartością każdej z funkcji jest 3. min(3, abs(-3), m a x ( r o u n d ( 2 . 7 ) , c e i l ( 2 . 3 ) , f l o o r ( 3 . 9 ) ) )
W jaki sposób są naprawdę tworzone funkcje PHP? Może to interesować programistów C lub tych, którzy chcą poznać wewnętrzną budową PHP. Możemy chyba zdradzić, dlaczego wiele funkcji PHP działa identycznie jak ich odpowiedniki w C. Poniżej aktualna definicja funkcji PHP ceil, która konwertuje liczbę double na najmniejszą liczbę całkowitą, która jest od niej większa lub jej równa. PHP_FUNCTION(ceil) {
zval ** value; if (ARG_COUNT(ht)!=1I|getParametersEx(1, svalue)==FAILURE) { WRONG_PARAM_COUNT; )
convert_scalar_to_number_ex (value) ; if ((*value)->type == IS DOUBLE) ( TT
if
l l-^ciTne] -> Abe == j
DOnprEJ
( R v a l u e ) - > t y p e == IS_DOUBLE)
/
{
else if (("value)->type == IS_LONG) ( RETURN_LONG((*value)->value.Ival); ) RETURN_FALSE; }
Fragmenty pisane wielkimi literami (włączając w to deklarację PHP_FUNCTION) są makrami specyficznymi dla szkieletu kodu PHP. Większość kodu jest napisana w prostym języku C. Kod może wydawać się zwarty i skomplikowany, ale wiele instrukcji jest związanych ze specjalnym traktowaniem typów w PHP. Funkcja ta działa w następujący sposób: 1. Pobierane i policzone są argumenty wywołania funkcji celi o. Jeżeli liczba argumentów jest inna niż ±, funkcja kończy się błędem. 2. Argument jest konwertowany do liczby, jeżeli jest typem skalarnym innym niż liczba. Ma zastosowanie w sytuacji wywołania funkcji z ciągiem znaków np.: celi ( " 5 . 4 " ) . 3. Argument numeryczny jest sprawdzany, czy jest typu long (inaczej mówiąc integer). Jeżeli jest to long, zwracana jest jego wartość. 4. Interesującym nas przypadkiem jest wywołanie funkcji z argumentem double. Jeśli to się zdarzy, wywoływana jest funkcja C ceil. Jej wynik jest konwertowany do typu long. Następnie jest umieszczana w zmiennej long w sensie PHP i zwracana. Inaczej mówiąc, implementacja PHP funkcji ceil jest funkcją C ceil wzbogaconą o konwersję typów i sprawdzanie argumentów. Dlatego właśnie wiele z funkcji PHP działa identycznie jak ich odpowiedniki w C.
184_________________________________________Część
l
»
Podstawy
PHP
Konwersja podstawy Domyślną podstawą liczb w PHP, używaną do czytania i drukowania, jest 10. Dodatkowo można wczytywać liczby ósemkowe (o podstawie 8), umieszczając dodatkowe O na początku liczby, lub liczby szesnastkowe (o podstawie 16), rozpoczynając liczbę znakami Ox. Więcej o formatach wczytywania liczb, notacji oktalnej i heksadecy-
L
malnej, w rozdziale 6.
Po wczytaniu liczby są reprezentowane w pamięci w formacie binarnym. Wszystkie
podstawowe operacje matematyczne są realizowane na liczbach o podstawie 2. PHP posiada funkcje konwertujące różne podstawy. Zamieściliśmy je w tabeli 10.3. Tabela 10.3.
Funkcje konwersji podstawy Funkcja
Opis
BinDec ( )
Wymaga ciągu zawierającego binarną reprezentację liczby jako argumentu; zwraca ciąg zawierający reprezentację tej liczby o podstawie 10
DecBin ( )
Działa jak BinDec ( ) , ale konwertuje podstawę 10 na 2
OctDec ( )
Działa jak BinDec ( ) , ale konwertuje podstawę 8 na 10
DecOct ( )
Działa jak BinDec ( ) , ale konwertuje podstawę 10 na 8
HexDec ( )
Działa jak BinDec ( ) , ale konwertuje podstawę 16 na 10
DecHex ( )
Działa jak BinDec ( ) , ale konwertuje podstawę 10 na 16
base_convert ( )
Jako argumentu wymaga ciągu (liczby do skonwertowania) i dwóch liczb, określających podstawę liczby z pierwszego argumentu oraz wymaganą podstawę. Zwraca ciąg
reprezentujący liczbę o żądanej podstawie. Cyfry większe od 9 są reprezentowane jako litery od a do z. Obie podstawy muszą zawierać się pomiędzy 2 a 36
Wszystkie funkcje konwersji podstawy mają określone przeznaczenie, konwertując jedną określoną podstawę na inną. Jedynie funkcja base_convert ( ) pozwala na podanie dowolnej podstawy początkowej i końcowej. Przypatrzmy się działaniu funkcji base_ convert(). function display_bases{ $start_string, $start_base) { for ($new_base - 2 ; $new_base <= 36 ; $new_base++) { $converted = base_convert(Sstart_string, 3start_base, $new_base); print( "$start_string o podstawie $start_base to $converted o podstawie $new_base ");
o podstawie 20 0 podstawie 20 o podstawie 20 o podstawie 20 o podstawie 20 o podstawie 20 o podstawie 20 0 podstawie 20 o podstawie 20 o podstawie 20 0 podstawie 20 o podstawie 20 o podstawie 20 0 podstawie 20 o podstawie 20 0 podstawie 20 o podstawie 20 0 podstawie 20 o podstawie 20 0 podstawie 20 0 podstawie 20
Ijj
podstawie 20 o podstawie 20 o podstawie 20 o podstawie 20 o podstawie 20 o podstawie 20 o podstawie 20 0
o podstawie 0 podstawie 0 podstawie o podstawie 0 podstawie o podstawie
to to to to to to to to to to to to to to to to to to to to to to
to to to to to to
20 to 20 to 20 to 20 to
20 to 20 to
1002121 o podstawie 3 30133 o podstawie 4 11144 o podstawie 5 3411 o podstawie 6 2221 o podstawie 7 1437 o podstawie 8 1077 o podstawie 9 799 o podstawie 10 667 o podstawie 11 567 o podstawie 12 496 0 podstawie 13 411 384 31f 2dO 287 241 Ijj Ihl Ie7 Ibh 197 16o
o podstawie 14 o podstawie 15 0 podstawie 16
o podstawie o podstawie o podstawie o podstawie
17
18 19 20 o podstawie 21 o podstawie 22 o podstawie 23 0 podstawie 24 o podstawie 25 14j 0 podstawie 26 12g o podstawie 27 lOf 0 podstawie 28 rg o podstawie 29 qj o podstawie 30 po o podstawie 31 ov o podstawie 32 o7 0 podstawie 33 nh o podstawie 34 mt o podstawie 35 m7 o podstawie 36
Funkcje konwersji podstawy oczekują, że liczba przekazana jako argument jest liczbą całkowitą, a nie rzeczywistą. Oznacza to, że nie możesz skonwertować binarnego „10.1" do dziesiętnego „2.5". W PHP 4.0 beta 3 funkcja base_convert o dawała nieprawidłowe wyniki, gdy otrzymała ciąg zawierający separator dziesiętny (interpretowała go jako 0).
Mimo że funkcje konwersji podstawy spodziewają się ciągu jako argumentu i zwracają ciąg, możesz użyć jako argumentu liczby dziesiętnej i polegać na konwersji typów PHP (przeczytaj ostrzeżenie poniżej). Inaczej mówiąc, oba wywołania DecBin ( " 1 2 3 4 " )
i DecBin (1234) dadzą ten sam wynik. Nie pomyl formatu odczytu liczby z jej reprezentacją. Dla przykładu, mimo że 10 o podstawie 16 jest równe 16 o podstawie 10, to wyrażenie HexDec(Oxio) daje w wyniku „22". Dlaczego? Sprawdźmy, jakie konwersje zachodzą. Podczas odczytywania 0x10 jest konwertowany do wewnętrznego formatu binarnego, następnie do ciągu (z postaci binarnej do postaci 16). 16 o podstawie 16 jest zamieniane na dziesiętne 22. Jeżeli chcesz, aby zaszła tylko jedna konwersja, powinieneś zapisać to wyrażenie HexDec (" i o " ) .
186_________________________________________Część l »
Podstawy PHP
Funkcje wykładnicze i logarytmy PHP zawiera funkcje logarytmiczne i wykładnicze, bazujące na podstawie 10 i e (tabela 10.4). Tabela 10.4. Funkcje wykładnicze
Funkcja
Opis
pow ( )
Wymaga dwóch argumentów numerycznych. Zwraca pierwszy argument podniesiony do potęgi określonej przez drugi argument. Wartością pow ( $ x , Sy) jest xy
exp O log ( ) logio { )
^^> \A
Wymaga jednego argumentu. Podnosi e do podanej potęgi. Wartością exp ( $ x ) jest e* Funkcja oblicza logarytm naturalny. Wymaga jednego argumentu i zwraca jego logarytm o podstawie e. Jeżeli ey=x, wartością log ( S x ) jest y Wymaga jednego argumentu i zwraca jego logarytm o podstawie 10. Jeżeli 10y=x, wartością logi O ($x) jest y
Stała matematyczna e (około 2,718) nie występuje w PHP, ale jej przybliżenie można uzyskać jako wynik funkcji log < i).
W przeciwieństwie do exp ( ) i podstawy e, nie ma funkcji o jednym argumencie, która podnosi 10 do odpowiedniej potęgi. Można użyć dwuargumentowej funkcji pow ( ) , podając liczbę 10 jako pierwszy argument. Możesz sprawdzić, że funkcje wykładnicze i podnoszenie do potęgi o tej samej podstawie są swoimi odwrotnościami. $test_449 = 449.0; $test_449 = pow(10, exp(log(loglO($test_449)))); print("test_449 wynosi $test_449 ");
Wykonanie tego fragmentu wyświetli w przeglądarce: t e s t _ 4 4 9 wynosi 4 4 9
Trygonometria Mimo że nie objaśniamy natury obliczeń wykonywanych przez omawiane funkcje, tym
razem zrobimy wyjątek (spójrz na przypis „Trygonometria w jednym akapicie"). Jeżeli
ktoś nie wie nic na temat trygonometrii, nic nie skorzysta z tego opisu.
PHP oferuje standardowy zestaw funkcji trygonometrycznych oraz stałą M_P1, która
jest przybliżeniem liczby pi, liczbą typu double i posiada wartość 3,1415926535898 (jest to chyba jedyna stała matematyczna w PHP). Stała ta może być używana wszędzie tam, gdzie jest potrzebna liczba/?; i może być używana zamiennie z funkcją pi ( ) .
Oba poniższe wyrażenia maj ą taką wartość: $liczba_pi = M_PI; $liczba_pi = pi();
Podstawowe funkcje trygonometryczne zebrane zostały w tabeli 10.5. Tabela 10.5. Funkcje trygonometryczne Funkcja
Opis
pi ( )
Nie wymaga argumentów i zwraca przybliżenie liczby/?/ (3,1415926535898). Może być używana zamiennie ze stalą M_PI
sin o
Wymaga argumentu numerycznego oznaczającego kąt w radianach i zwraca wartość sinusa podanego kąta jako liczbę double
cos ( )
Wymaga argumentu numerycznego oznaczającego kąt w radianach i zwraca wartość cosinusa podanego kąta jako liczbę double
tan ( )
Wymaga argumentu numerycznego oznaczającego kąt w radianach i zwraca wartość tangensa podanego kąta jako liczbę double
asin ( )
Wymaga argumentu numerycznego i zwraca arcus sinus argumentu w radianach. Wartość
argumentu może być liczbą z zakresu -1,0 do 1,0 (argument poza tym zakresem zwraca jako
wynik NaN — „nie liczba"). Wynik jest wartością z zakresu -pi/2 do pi/2 acos ( )
Wymaga argumentu numerycznego i zwraca arcus cosinus argumentu w radianach. Wartość argumentu może być liczbą z zakresu -1,0 do 1,0 (argument poza tym zakresem zwraca jako wynik NaN — „nie liczba"). Wynik jest wartością z zakresu od O do pi
atan ( )
Wymaga argumentu numerycznego i zwraca arcus tangens argumentu w radianach. Wynik jest wartością z zakresu -pi/2 do pi/2
atan2 ( )
Odmiana funkcji atan(), która wymaga dwóch argumentów. atan2($y, $x) jest identyczny
z atan($y/Sx), jeżeli $x jest dodatnie, ale kwadrat wyniku atan2 zależy od znaku $y oraz $x. Wynik funkcji jest z zakresu -pi do pi
Trygonometria w jednym akapicie
Wyobraźmy sobie okrąg o promieniu 1; jego środek znajduje się w punkcie o współrzędnych 0,0. Rozpocznij z „prawego końca" (współrzędne 1,0), mierząc odległość po okręgu przeciwnie do wskazówek zegara. Przykładowo odległość 2pi pozwoli na przemieszczenie się po całym okręgu, aż do punktu wyjścia. Dla każdej odległości funkcja sinus wskazuje wartość y współrzędnej, do której dotarłeś. Funkcja cosinus wskazuje wartość współrzędnej x, a funkcja tangens jest stosunkiem współrzędnej y i x. Funkcje arcus sinus, arcus cosinus i arcus tangens są w pewnym sensie odwrotnością funkcji podstawowych — zamieniają na powrót x, y i y/x na odległość po łuku, jaką trzeba przebyć, aby otrzymać taką wartość współrzędnej x, y lub ich stosunku. Ponieważ dodanie 2pi do dowolnej odległości przeniesie nas do tego samego punktu, funkcje odwrotne mogą mieć nieskończoną liczbę rozwiązań dla określonej danej (co zaprzecza definicji funkcji). Są ograniczone do długości połowy okręgu, co powoduje, że są w ten sposób prawidłowo zdefiniowane.
188_________________________________________Część
l
»
Podstawy
PHP
Zamiast tworzyć tabelę przykładowych wyników tych funkcji, napiszmy program, który automatycznie wyświetli wyniki w tabeli HTML. Na wydruku 10.1 zamieszczona jest ogólna funkcja wyświetlająca zestaw wyników jednoargumentowych funkcji działających na zbiorze argumentów. Następnie użyjemy tej funkcji do stworzenia tabeli przykładowych wyników działania funkcji trygonometrycznych i odwrotnych funkcji trygonometrycznych. Wynik działania na rysunku 10.1. Wydruk 10.1.
Wyświetlanie wyników działania funkcji trygonometrycznych___________________
Rysunek 10.1. Przykład działania funkcji trygonometrycznych
Na rysunku 10.1 pokazane są podstawo we funkcje trygonometryczne z zakresu danych od -5/4 pi do 5/4 pi oraz podstawowe odwrotne funkcje trygonometryczne w zakresie danych od —1,0 do 1,0. Duża wartość funkcji tangens jest spowodowana wartością mianownika, który powinien teoretycznie być równy zero, ale z powodu błędów zaokrąglenia różni się od zera. Funkcja display_func_resuits o , pokazana na wydruku 10.1, korzysta z kilku sztuczek opisanych w poprzednim rozdziale: użycia zmiennej jako nazwy funkcji (opisanej pod koniec rozdziału 8.) oraz łączenia ciągów za pomocą operatora konkatenacji ('.') do połączenia ciągów w instrukcji print (opis w rozdziale 9.). W kodzie przedstawionym na wydruku 10.1 korzystamy ze „zmiennej funkcyjnej" wprowadzonej w PHP. Pozwala to na wywoływanie funkcji trygonometrycznych poprzez nazwy. Poprzednia wersja PHP pozwalała na takie wywoływanie własnych funkcji; w PHP 4 jest to nowość w odniesieniu do funkcji wbudowanych.
190_________________________________________Część l » Podstawy PHP 190
Liczby losowe Funkcje generujące liczby losowe w PHP zebrane zostały w tabeli 10.6. Jeżeli potrzebujesz więcej wyjaśnień na temat ich losowości, przeczytaj objaśnienia w dopisku. Tabela 10.6.
Funkcje liczb losowych Funkcja
srand
Opis
()
Jako argumentu wymaga dodatniej liczby całkowitej i inicjuje nią generator liczb losowych
rand < >
Wywołana bez argumentów zwraca liczbę „losową" z zakresu od O do RAND_MAX (może zostać odczytana za pomocą funkcji getrandmax ( ) ) . Funkcja może być wywołana z dwoma argumentami ograniczającymi zakres losowanych liczb: pierwszy z nich jest minimum, drugi maksimum
getrandmax ( )
Zwraca największą liczbę, jaką można uzyskać za pomocą funkcji r a n d ( )
mt_srand ( )
jak srand ( ) , ale korzysta z „lepszego" generatora liczb losowych
mt_rand ()
j a k r a n d (), ale korzysta z „lepszego" generatora liczb losowych
mt_getrandmax ( )
Zwraca największą liczbę, jaką można uzyskać za pomocą funkcji mt_rand ( )
Istnieją dwa generatory liczb losowych, każdy z nich ma trzy takie same funkcje: inicjującą, zwracającą liczbę losową oraz zwracającą największą liczbę, jaką można uzyskać z generatora. Konkretna funkcja losowa może zależeć od bibliotek, z którymi został skompilowany PHP. W odróżnieniu od tego generator mt_rand ( ) używa zawsze tej samej funkcji losującej („Mersenne Twister"). Jej autor dowodzi w dokumentacji, że jest ona szybsza i „bardziej losowa" (w sensie kryptograficznym) od funkcji rand ( ) . Nie ma powodu
nie wierzyć autorowi, użyjemy zatem mt rand ( ) zamiast rand ( ) . W niektórych wersjach PHP w zależności od platformy otrzymuje się pozornie losowe liczby, jeżeli nie zainicjuje się wcześniej generatora. Nie można na tym polegać zarówno z powodu niemożności przeniesienia takiego rozwiązania, jak i dlatego, że działanie niezainicjowanego generatora nie ma gwarancji.
Inicjowanie generatora Typowym sposobem inicjowania generatorów liczb pseudolosowych w PHP jest użycie funkcji mt_srand ( ) lub srand ( ) : mt_srand( (double)microtime()*10000000);
Funkcje generujące liczby losowe, dostępne w PHP są tak naprawdę implementowane na bazie generatorów liczb pseudolosowych. Dzieje się tak, ponieważ architektura komputera bazuje na maszynie deterministycznej, która zawsze daje te same wyniki przy tych samych danych wejściowych. Nie ma więc miejsca na losowość (mówimy o idealnych komputerach, a nie o użytkowanych codziennie). Można sobie wyobrazić podłączenie konwencjonalnego komputera do źródła losowych danych, jak na przykład mechanicznego wyrzutnika monet czy urządzenia obserwującego efekty kwantowe, ale nie wszyscy mają do nich dostęp. Trzeba więc korzystać z generatorów liczb pseudolosowych, które produkują deterministyczną sekwencję liczb, dostatecznie losowych do większości zastosowań. Ich działanie jest inicjowane poprzez podanie liczby początkowej (ziarna) do odpowiedniej funkcji w celu wygenerowania pierwszej liczby z sekwencji. Kolejne liczby są wynikiem wykonania tej samej funkcji na poprzednio uzyskanej liczbie. Sekwencja w końcu się powtórzy, ale dobra funkcja wygeneruje bardzo długi ciąg liczb, zanim rozpocznie powtarzanie tej sekwencji. W jaki sposób wybrać liczbę inicjującą generator? Jeżeli na stałe zaszyjesz w kodzie wartość ziarna, za każdym uruchomieniem programu dostaniesz tę samą sekwencję liczb. Typowa technika inicjowania generatora polega na użyciu szybko zmieniającej się liczby pochodzącej z zegara systemowego. Mimo że liczba ta nie jest losowa, zmienia się tak szybko, że nawet kolejne uruchomienia programu spowodują inną wartość inicjującą generator.
Liczba mikrosekund, które upłynęły od ostatniej „pełnej" sekundy, inicjuje generator. Możesz używać konstrukcji, nie wnikając w szczegóły działania. Umieść taki wiersz na dowolnej stronie PHP wykonywanej tylko raz przed odwołaniem do funkcji mt_rand ( ) lub rand ( ) . Za każdym uruchomieniem strony otrzymasz różne losowe sekwencje. Poniższy przykład używa tej techniki inicjowania: print ("Inicjowanie generatora "); mt_srand( (double) microtime 0*10000000);
p r i n t ( " B e z argumentów:". m t _ r a n d ( ) . " < B R > " ) ; p r i n t ( " B e z a r g u m e n t ó w : " . m t _ r a n d ( ) . " "); print("Bez argumentów:". mt_rand(). " "); p r i n t C ' Z dwoma a r g u m e n t a m i : " . m t _ r a n d ( 2 7 , 3 1 ) . " < B R > " ) ; p r i n t ( " Z dwoma a r g u m e n t a m i : " . m t _ r a n d ( 2 7 , 3 1 ) . " < B R > " ) ; printC'Z dwoma argumentami:". m t _ r a n d ( 2 7 , 3 1 ) . " ");
Wynik powyższego fragmentu jest następujący: Inicjowanie generatora Bez argumentów: 415068444
Bez argumentów: 530864282
Bez argumentów: 1823883289
Z dwoma argumentami: 29 Z dwoma argumentami: 31 Z dwoma argumentami: 30
Uruchamiając taki program, otrzymasz liczby różniące się od podanych, ponieważ ten sposób inicjowania generatora daje odmienne wyniki.
192_________________________________________Część
l
»
Podstawy
PHP
W niektórych starych wersjach PHP 3 funkcja rand ( ) ignorowała przekazane argumenty i zawsze zwracała wartość pomiędzy O i getrandmax ( ) (podobnie wczesne implementacje dla Windows). Jeżeli twoja wersja ma tę usterkę, możesz napisać własną ograniczoną wersję funkcji rand ( ) : function mo]_rand( $min, $max) { return (rand() % (($max - $min) +1) +$min); )
W przeciwieństwie do rand ( ) funkcja ta zawsze wymaga argumentów min i max. Mimo że funkcje generatora liczb pseudolosowych zwracają tylko liczby całkowite, łatwo możesz sprowadzić je do postaci liczb rzeczywistych z zakresu od 0,0 do 1,0 za pomocą wyrażenia rand o / getrandmax ( ) . Następnie możesz skalować i przesuwać otrzymaną liczbę, aby uzyskać żądany zakres (na przykład dla liczb pomiędzy 100,0 a 120,0 należy użyć wyrażenia 100.0 + 2 0 . 0 * (rand O / getrandmax() ).
Przykład: losowy wybór Użyjemy teraz funkcji losujących do czegoś użytecznego. Poniższe dwie funkcje pozwalaj ą stworzyć ciąg z losowych liter, który może być użyty jako losowe hasło lub nazwa użytkownika. function random_char($string) { Slength = strlen(Sstring); Sposition = mt_rand(0, Slength - 1); return (Sstring[$position]); }
function random_string($charset_string, Slength) f Sreturn_string = ""; // pusty ciąg for ($x = O ; $x < Slength ; $x + + ) $return_string .= random_char($charset_string); return (Sreturn^string); l
Funkcja random_char ( ) wybiera znak (właściwie podciąg o długości 1) z ciągu wejściowego. Zrealizowaliśmy to ograniczając zakres losowanych liczb do długości ciągu i zwracając znak znajdujący się na wylosowanej pozycji. Funkcja random_string o wywołuje random_char ( ) tyle razy, ile określiliśmy w argumencie wywołania, łącząc
wylosowane litery w ciąg o żądanej długości.
Aby zademonstrować działanie tego kodu, zainicjujemy generator i po zdefiniowaniu liter, na których działają funkcje, wywołamy kilka razy random_string ( ) :
W wyniku otrzymaliśmy: Losowy ciąg: efwwrpzd Losowy ciąg: zwewvdck
Losowy ciąg: jynhricn
W tym przykładzie tylko raz zainicjowaliśmy generator za pomocą wartości pobranej z zegara systemowego. Popatrzmy, co stanie się, jeżeli popełnimy błąd i będziemy wielokrotnie inicjować generator tą samą wartością: mt_srand(43); $random_string = random_string(Scharset, 8); print("Losowy ciąg: $random_string "); mt_srand(43); $random_string = random_string($charset, 8); print("Losowy ciąg: $random_string ") ; mt_srand(43); $random_string = random_string(Scharset, 8) ; print("Losowy ciąg: $random_string ") ;
Ponieważ generowana sekwencja zależy od wartości ziarna generatora, za każdym razem dostaniemy te same wyniki: Losowy ciąg: qgkxvurw
Losowy ciąg: qgkxvurw Losowy ciąg: qgkxvurw
W tym przykładzie wybieraliśmy losowe litery z ciągu, lecz proces ten może zostać uogólniony do wybierania elementów np. z tablicy (lub dowolnego losowego elementu zbioru). Musisz zdefiniować przestrzeń elementów, sposób ich ponumerowania i wybrania na podstawie wylosowanej liczby. Następnie można użyć funkcji rand ( ) lub mt_rand ( ) do wyboru losowego numeru porządkowego elementu.
Arytmetyka o dowolnej dokładności Typy integer i double są wy starczające dla większości zadań matematycznych, które występują przy tworzeniu witryn WWW. Każdy z tych typów jest przyporządkowany stałej ilości pamięci komputera, więc ich rozmiar i dokładność zależą od architektury
serwera. Zwykle liczby całkowite mają zakres od -231 - l do 2 31 - l, liczby double mają 13 lub 14 cyfr. Do zadań wymagających większej dokładności PHP zapewnia zestaw funkcji matematycznych o dowolnej dokładności (znanych jako funkcje „BC" od nazwy narzędzia Unixa do obliczenia o dowolnej dokładności).
Aby umieścić w PHP funkcje o dowolnej dokładności, trzeba podczas kompilacji włączyć flagę —enabie-bcmath. Aby sprawdzić, czy funkcje są dostępne, dołącz do dowolnego skryptu wiersz bcadd("i", "i") . Jeżeli otrzymasz błąd nieistniejącej funkcji, musisz ponownie skonfigurować PHP.
Funkcje BC wymagają ciągu jako argumentu, a także zwracają ciągi, zamiast używać typów numerycznych o stałej wielkości. Ponieważ ciągi w PHP są ograniczone jedynie dostępną pamięcią, oznacza to, że liczby mogą mieć dowolną długość. Obliczenia wykonywane przez te funkcje są realizowane na liczbach dziesiętnych. Funkcje BC są dokładne w działaniu na liczbach całkowitych, używają tylu cyfr, ilu potrzeba. W przypadku działań na liczbach rzeczywistych obliczenia są realizowane z taką dokładnością,
jakiej zażądasz. Funkcje BC przedstawione sąw tabeli 10.7. Tabela 10.7.
Funkcje matematyczne o dowolnej dokładności (BC) Funkcja
Opis
bcadd ( )
Wymaga dwóch argumentów reprezentujących liczby oraz opcjonalnego argumentu oznaczającego dokładność. Zwraca sumę dwóch pierwszych argumentów jako ciąg,
z określoną przez argument oznaczający dokładność liczbą cyfr po przecinku. Jeżeli nie zostanie podany trzeci argument, funkcja użyje domyślnej dokładności, którą ustawia się za pomocą funkcji bcscale ( )
bcsub ( }
Podobna do bcadd ( ) , ale zwraca różnicę pierwszego i drugiego argumentu
bcmul ( )
Podobna do bcadd ( ) , ale zwraca iloczyn pierwszego i drugiego argumentu
bcdiv ( )
Podobna do bcadd ( ) , ale zwraca wynik dzielenia pierwszego argumentu przez drugi
bcmod ( )
Zwraca resztę z dzielenia pierwszego argumentu przez drugi. Ponieważ wynik jest całkowity, dokładność jest niepotrzebna
bcpow ( )
Podnosi pierwszy argument do potęgi określonej drugim argumentem. Jeżeli został podany trzeci argument, określa liczbę miejsc dziesiętnych
bcsqrt ( ) bcscale ()
Zwraca pierwiastek kwadratowy argumentu z liczbą miejsc dziesiętnych określoną przez opcjonalny drugi argument Ustawia domyślną dokładność dla kolejnych wywołań funkcji BC
Większość funkcji posiada opcjonalną dokładność obliczeń jako ostatni argument, określającą, ile liczb po przecinku znajdzie się w wyniku. Jeżeli ten argument nie zostanie podany, przyjęta będzie domyślna dokładność, która jest ustawiana wywołaniem funkcji bcscale ( ) . Przed wywołaniem funkcji bcscale ( ) dokładność jest ustawiona na wartość umieszczoną w pliku php.ini.
Przykład użycia funkcji o dowolnej dokładności Poniżej znajduje się przykład użycia funkcji BC do obliczeń na liczbach całkowitych.
Wynik działania tego fragmentu jest następujący: 1 do potęgi l wynosi l 2 do potęgi 2 wynosi 4 3 do potęgi 3 wynosi 27
4 do potęgi 4 wynosi 256 5 do potęgi 5 wynosi 3125
6 do potęgi 6 wynosi 46656 7 do potęgi 7 wynosi 823543 8 do potęgi 8 wynosi 16777216 9 do potęgi 9 wynosi 387420489 10 do potęgi 10 wynosi 10000000000 11 do potęgi 11 wynosi 285311670611 12 do potęgi 12 wynosi 8916100448256 13 do potęgi 13 wynosi 302875106592253
14 do potęgi 14 wynosi 11112006825558016 15 do potęgi 15 wynosi 437893890380859375
16 17 18 19 20
21 22 23 24
do do do do do
do do do do
potęgi potęgi potęgi potęgi potęgi
potęgi potęgi potęgi potęgi
16 wynosi 18446744073709551616 17 wynosi 827240261886336764177 18 wynosi 39346408075296537575424 19 wynosi 1978419655660313589123979 20 wynosi i04857600000000000000000000
Jeżeli użyjemy do tych obliczeń zwykłego typu całkowitego, zakres liczb całkowitych zostanie przekroczony; pod koniec pętli obliczenia będą wykonywane na przybliżonych
liczbach zmiennoprzecinkowych.
Konwersja obliczeń na dowolną dokładność Prześledzimy teraz, jak zamienić istniejące wyrażenie matematyczne na program korzystający z funkcji o dowolnej dokładności. Kolejne przybliżenia liczby/?/: sqrt(12 - ( 1 2 / 2 2 )
+
(12/32) - (12/42)
+ 12/5 2 )
- ...)
Ciąg ten nie zbiega się wystarczająco szybko, ale jest bardzo prosty. function pi_approx( $iterations, $print_frequency) { $squaręd_approx = 12; $next_sign = -1; $dęnom - 2; for ($iter = 0; $iter < $iterations; $iter++) t $squared_approx += $next_sign * 127(pow($denom, 2}); $denom++; Snext_sign - -$next_sign; if (Sdęnom % $print_frequency == 0) ( $estimate = sqrt($squared_approx);
print("$denom iteracja: $estimate ");
196______________________________________Część l » Podstawy PHP Program co pewien czas wypisuje bieżące przybliżenie liczby pi, więc możemy sprawdzić w jaki sposób jest obliczana. Wywołajmy funkcję, wypisując dla porównania wartość liczby pi zaszytej w PHP. pi_approx(10000, 1000); print ("Wartość PHP: ". pil). " ");
Wynik działania jest następujący: 1000 2000 3000 4000 5000
3.1415926653804 10000 iteracja: 3.1415926631401 Wartość PHP: 3.1415926535898
Aby zamienić naszą funkcję na wersję używającą funkcji dowolnej dokładności, należy wymienić wszystkie funkcje matematyczne i operatory na odpowiadające im funkcje BC. function pi_approx_bc( $iterations, $print_frequency, Sscale) ( Ssquared_approx = "12"; $next_sign = -1;
Mimo że funkcje BC wymagają ciągu jako argumentu, można zawsze użyć w ich miej-
sce zwykłych liczb, a PHP skonwertuje je do postaci ciągów. Nie używamy funkcji BC
do prostych obliczeń, które nie wymagają dużej dokładności (na przykład pozostawiliśmy $denom++, nie zamieniliśmy go na bcadd ($denom, l)). Dodaliśmy również argument określający dokładność, z jaką realizowane są obliczenia w każdej z funkcji BC. Niestety Autorzy nie mieli tyle cierpliwości, aby obliczyć za pomocą tego ciągu liczbę pi z dokładnością dostępną w PHP. Poniżej kilka ostatnich wyników dla wywołania pi_approx_bc(125000,
Otrzymane wyniki różnią się od wartości pi zaszytej w PHP. Wiąże się to z wybranym ciągiem przybliżającym, a nie z funkcjami BC. Można j ą przybliżyć za pomocą bardziej skomplikowanych i szybszych ciągów. print("Pierwiastek kwadratowy z dwóch wynosi:" . bcsqrt(2, 40));
daje dużo większą dokładność, niż możemy uzyskać z liczb double: Pierwiastek kwadratowy z dwóch wynosi: 1.4142135623730950488016887242096980785696
Podsumowanie Zagadnienia matematyki omówione w niniejszym rozdziale zostały zebrane w tabeli 10.8. Tabela 10.8.
Zestaw operatorów i funkcji matematycznych w PHP Zagadnienie
Operatory ++ i -- zmieniają wartość zmiennych numerycznych, odpowiednio zwiększając lub zmniejszając o jeden. Wartość wyrażenia w postaci przyrostkowej ($var++) jest równa wartości zmiennej przed zmianą wartości.
arytmetyczne
i zmiennoprzecinkowych
Wartość wyrażenia w postaci przedrostkowej (+ + $var) jest równa wartości zmiennej po zmianie wartości
Operatory przypisania
Każdy operator arytmetyczny (na przykład ' + ') posiada odpowiadający mu operator przypisania ( ' + = ' ) • Wyrażenie $count += 5 jest równoważne $count = Scount + 5
Operatory porównania <, <=, >, >=, ==, ! =. Operator === jest prawdziwy, gdy oba argumenty są równe i mają ten sam typ Podstawowe
floor (), ceil () oraz round () konwertują liczbę double na całkowitą, min (),
funkcje matematyczne
ma
Podstawowe
funkcje konwersji
x ( ) wybierają największą i najmniejszą wartość podanego parametru, abs ( )
(e podniesione do odpowiedniej potęgi) oraz pow ( ) (pierwszy argument podniesiony do potęgi określonej przez drugi) Funkcje trygonometryczne
pi (} (oraz stała M_PI), sin (), cos (), tan (), acos (), asin (}, atan () oraz atan2 ( ) (dwuargumentowa wersja atan ( ) )
Funkcje arytmetyki Funkcje realizujące działania arytmetyczne na ciągach dowolnej długości, o dowolnej dokładności (BC) reprezentujących liczby całkowite oraz rzeczywiste: bcadd ( ) , bcsub ( ) , bcmult ( ) , bcdiv ( ) , bcmod ( ) , bcpow ( ) , bcsqrt ( ) . Większość Z nich
posiada opcjonalny argument oznaczający dokładność. Domyślna dokładność jest ustawiana funkcją bcscale ( )
Rozdział 11.
Tablice i funkcje operujące na tablicach W tym rozdziale:
* Działanie tablic w PHP * Użycie tablic wielowymiarowych
4 Imitowanie innych struktur danych za pomocą tablic 4 Sortowanie i inne transformacje Tablice są jedną z najlepszych i najbardziej elastycznych funkcji PHP. W przeciwieństwie do tab li c-wektorów z innych języków programowania (C, C++, Pascal), tablice PHP mogą przechowywać dane rozmaitych typów i automatycznie organizować je w różny sposób. W tym rozdziale opisaliśmy dosyć dokładnie tablice i funkcje na nich operujące. Jeżeli potrzebujesz szybkiego wprowadzenia — przeczytaj rozdział 6.
Uwaga! Mimo że tablice istnieją już w PHP od jakiegoś czasu i działają w ten sam sposób jak w PHP 3, niektóre z opisanych w tym rozdziale funkcji są wprowadzone w PHP 4.
Użycie tablic W tym rozdziale będziemy m.in. objaśniali sposób działania tablic i omawiali wszystkie funkcje wbudowane, przeznaczone do manipulacji tablicami. Zanim to nastąpi, wyliczmy zastosowania tablic w kodzie stron WWW.
200_________________________________________Część l
»
Podstawy PHP
* Wiele wbudowanych zmiennych środowiskowych PHP to tablice (na przykład $HTTP_COOKIE_VARS, która zawiera wszystkie zmienne i ich wartości zapamiętane w cookies w komputerze klienta). Jeżeli chcesz korzystać z tych zmiennych, powinieneś wiedzieć, w jaki sposób odwoływać się do elementów tablic. •* Większość funkcji związanych z bazami danych przenosi informacje w postaci tablic, tworząc poręczny pakiet danych. •* W jednej tablicy można łatwo przekazać zbiór argumentów z formularza
HTML z jednej strony do drugiej (popatrz do następnego rozdziału).
* Tablice są dobrym narzędziem manipulacji danymi (sortowanie, zliczanie itp.).
W prawie każdej sytuacji, gdy odwołujesz się do kilku danych, które mogą zostać spakowane do jednej struktury i używane w jednorodny sposób, użycie tablic będzie właściwym posunięciem.
Czym są tablice PHP? Tablice w PHP są tablicami asocjacyjnymi, rozszerzonymi o kilka dodatkowych mechanizmów. Słowo „asocjacyjne" oznacza, że tablice te zapamiętują dane w połączeniu z ich wartością kluczową, a nie w porządku liniowym. Tablice w innych językach programowania są wektorami, nie tablicami asocjacyjnymi (więcej na ten temat w „Tablice
asocjacyjne a wektory"). Jeżeli zapisujesz do tablicy element wraz z kluczem, wartość elementu można odczytać korzystając z wartości klucza. Zapisanie do tablicy jest bar-
dzo proste:
$ w o j e w o d z t w o [ ' G l i w i c e ' ] = 'Śląskie';
Instrukcja taka zapamiętuje element 'śląskie' w tablicy $wojewodztwo w połączeniu z kluczem ' Gliwice '. Po zapisaniu tego elementu można odszukać zapisaną wartość za pomocą wartości klucza: Swojew = $wojewodztwo['Gliwice'];
// ma wartość 'Śląskie'
To wystarczy, aby używać tablic do zapamiętywania par klucz i wartość. Jeżeli chcesz zapamiętywać wartości w porządku numerycznym, musisz użyć liczb jako wartości klucza: $tablica[l] = 'Pierwszy element'; $tablica[2] = 'Drugi element';
Oprócz zapamiętywania par klucz i wartość, procedury obsługi tablic zawierają mechanizmy pozwalające na traktowanie tablic jak innych struktur danych. Tablice mogą być wielowymiarowe, co pozwala na zapisywanie wartości w połączeniu z sekwencją wartości kluczowych, a nie tylko z pojedynczą wartością. Tablice mogą automatycznie utrzymywać alfabetyczny porządek zapisywanych elementów, niezależnie od wartości
ich klucza. Pozwala to na traktowanie tablic jak list. Przybliżymy te aspekty działania tablic omawiając funkcje o specyficznych własnościach.
Rozdział 11.
*
Tablice i funkcje operujące na tablicach_______________________201
Tablice asocjacyjne a wektory
Jeżeli programowałeś przy użyciu języków takich jak C, C++ i Pascal, używałeś prawdopodobnie innej definicji słowa „tablica", która nie pasuje do określania tablic w PHP. Dokładniejszym określeniem tablic w C jest wektor, a tablice w PHP to tablice asocjacyjne. W wektorach wszystkie elementy muszą być tego samego typu; zwykle kompilator musi znać rozmiar wektora. Dla przykładu: w C możesz zadeklarować tablicę na 100 liczb zmiennoprzecinkowych o podwójnej precyzji za pomocą wyrażenia: double tablica[100];
// to nie jest PHP
Ograniczenie do jednego typu oraz deklaracja rozmiaru dają dodatkowe korzyści: wektory są bardzo szybkie, zarówno podczas zapisywania, jak i przeszukiwania. Dzieje się tak, ponieważ kompilator umieszcza taką tablicę w ciągłym bloku pamięci, o wielkości równej wielkości jednego elementu pomnożonej o liczbę elementów. Pozwala to na błyskawiczne odszukanie przez język programowania odpowiedniego fragmentu pamięci. Wystarczy znać adres początku tablicy, rozmiar elementu i indeks interesującego nas elementu, aby bezpośrednio obliczyć adres elementu w pamięci. W PHP tablice są asocjacyjne. Nie mają stałej liczby elementów, PHP tworzy miejsce na nowe elementy w momencie zapisywania ich do tablicy. Nie jest również wymagane, aby elementy tablicy były tego samego typu. Mają tę samą własność zmiany typu, jaką mają zmienne w PHP; możesz przypisać do komórki tablicy dowolną wartość. Ponieważ wektory umieszczają wartości w numerycznym porządku „kluczy", używanych do przeszukiwania i zapisywania danych, muszą być one liczbami całkowitymi. Tablice PHP mogą posiadać klucze dowolnego typu, mogą to być np. ciągi. Można wykonać kolejne przypisania, np.: Stablica[l] = 1; $tablica['orange'] = 2; $tablica[3] = 3;
Wynikiem wykonania tych wierszy programu jest tablica zawierająca trzy war-
tości (l, 2, 3) połączone z kluczami (l,
' o r a n g e ' , 3).
Elastyczność tablic asocjacyjnych jest okupiona sporymi kosztami, ponieważ wykonywanie kodu do momentu obliczenia adresu interesującego nas elementu zabiera więcej czasu niż w analogicznym przypadku dla wektorów. W większości zastosowań skryptów WWW ten dodatkowy czas nie gra zbyt wielkiej roli. Ponieważ liczby całkowite mogą być stosowane jako klucze w tablicy asocjacyjnej, można imitować działanie wektora, używając wartości całkowitych jako kluczy.
Dla programistów Perl. Tablice w PHP bardzo przypominają tablice asocjacyjne w Perl, z niewielkimi różnicami składniowymi. Po pierwsze, wszystkie zmienne w PHP, a nie tylko zmienne skalarne, rozpoczynają
202_________________________________________Część l
*
Podstawy PHP
się znakiem $. Po drugie, mimo że tablica jest asocjacyjna, indeksy są umieszczane w nawiasach kwadratowych ([]), a nie w klamrowych ({}). Nie ma tablic indeksowanych tylko liczbami całkowitymi. Konwencja, jest używanie liczb całkowitych jako indeksów asocjacyjnych, a tablica utrzymuje własny porządek dla potrzeb iteracji. Dla programistów C++. Tablice asocjacyjne pozwalają zrealizować niektóre z zadań, do których w C++ trzeba użyć biblioteki szablonów. Dzieje się tak, ponieważ stosowanie szablonów jest związane z uniknięciem podawania określonego typu danych. System typów PHP umożliwia pisanie ogólnych algorytmów, które przeglądają zawartość tablicy bez określania typu elementów.
Dla programistów znających inne języki programowania. PHP nie wymaga wielu rodzajów struktur danych z powodu dużej elastyczności tablic PHP. Wybierając odpowiedni podzbiór funkcji operujących na tablicach, można za pomocą tablic imitować inne struktury danych, takie jak wektory, struktury i rekordy, listy, tablice mieszające lub stosy i kolejki. Takie struktury danych w innych językach programowania wymagają własnego typu danych lub skomplikowanych funkcji języka programowania: użycia wskaźników, samodzielnego zarządzania pamięcią.
Tworzenie tablic W skrypcie PHP można utworzysz tablicę na trzy różne sposoby: przypisując wartość
do jednego klucza (tworząc ją tajnie), używając konstrukcji array ( ) oraz wywołując funkcję zwracającą tablicę jako wartość.
Bezpośrednie przypisanie Najprostszą metodą utworzenia tablicy jest przypisanie wartości do zmiennej mającej
być tablicą:
Stablicafl] = "Pierwszy element właśnie utworzonej tablicy";
Jeżeli $tablica była niezainicjowaną zmienną (lub zmienną nie będącą tablicą), po wykonaniu tego wiersza będzie tablicą z jednym elementem. Jeżeli zmienna $tablica
była już tablicą, zostanie w niej zapamiętany ciąg wraz z kluczem o wartości całkowitej 1. Jeżeli do tej pory nie był on związany z żadną wartością, zostanie utworzony nowy element tablicy do przechowywania naszego ciągu. Jeżeli istniała wartość związana
z kluczem l, zostanie nadpisana. Można również przypisywać wartości do tablicy bez podawania indeksu: $tablica [ ] (co zostanie opisane poniżej).
Rozdział 11. » Tablice i funkcje operujące na tablicach_______________________203
Konstrukcja array() Innym sposobem tworzenia tablicy jest użycie konstrukcji array ( ) , która tworzy nową tablicę, zawierającą podane jako argumenty wartości i ich klucze. Prostsza wersja konstrukcji array () zawiera tylko listę wartości zapisywanych do tablicy, bez określania ich kluczy. Wynikiem jest tablica z wartościami skojarzonymi z kluczami całkowitymi, rozpoczynającymi się od 0. Na przykład wyrażenie: $owoce = array('jabłko', 'pomarańcza 1 , 'banan', 'gruszka'};
spowoduje zapisanie w tablicy $owoce czterech elementów ( ' j a b ł k o ' , 'pomarańc z a ' , ' b a n a n 1 , ' g r u s z k a ' ) , z indeksami O, l, 2 oraz 3. Tablica dodatkowo pamięta
porządek, w którym zostały zapisane elementy (patrz część o iteracji). Przypisanie do zmiennej $owoce ma takie samo działanie, jak poniższe instrukcje: $owoce[0] = 'jabłko'; $owoce[l] = 'pomarańcza';
$owoce(2) = 'banan'; $owoce[3] = 'gruszka';
Ten sam efekt można osiągnąć opuszczając indeksy w przypisaniu: $owoce[] = 'jabłko';
$owoce[] = 'pomarańcza';
$owoce[] = 'banan'; $owoce[] = 'gruszka';
W tym przypadku PHP przyjmuje, że dodajesz sekwencję elementów, które powinny mieć indeksy numeryczne rozpoczynające się od 0. Dygresja. Domyślnie indeksy numeryczne rozpoczynają się od zera. Jest to konwencja obowiązująca dla tablic w większości języków programowania. Nie jesteśmy pewni, dlaczego komputerowcy rozpoczynają liczenie od O (matematycy np. od 1), ale może mieć to związek z arytmetyką wskaźników, która oblicza adresy pamięci dla elementów wektorów. Adresy kolejnych elementów tych tablic są odszukiwane przez dodanie coraz większych wartości przesunięcia do adresu tablicy, a pierwszy element tablicy posiada przesunięcie zero (ponieważ pierwszy element ma adres tablicy).
Podawanie indeksów przy użyciu array() W konstrukcji array ( ) indeksy przypisywane do naszych elementów są liczbami całkowitymi o wartościach rozpoczynających się od zera. Można jednak użyć specjalnej składni konstrukcji array ( ) używanej do definiowania kluczy wstawianych elementów. Zamiast wartości elementów rozdzielanych przecinkami, podaje się pary klucz i wartość rozdzielone przecinkami, a wartość jest oddzielona od klucza symbolem =>.
204___________________________________________Część l
»
Podstawy PHP
Przeanalizujmy następującą instrukcję: Sowoce = a r r a y l d => ' j a b ł k o ' , l => ' p o m a r a ń c z a ' , 2 => ' b a n a n ' , 3 => ' g r u s z k a ' ) ;
Wykonanie tego wiersza da ten sam efekt. Każdy z ciągów zostanie zapisany w tablicy i skojarzony z indeksami O, 1,2, 3. Możesz użyć tej samej składni do zapamiętania tych elementów z innymi kluczami: $owoce = array('czerwony' => 'jabłko', 'pomarańczowy' => 'pomarańcza', 'żółty' => 'banan', 'zielony' => 'gruszka');
Cztery elementy, w tym samym porządku, indeksowane są kolorem, a nie liczbą. Aby odczytać na przykład nazwę żółtego owocu, można użyć następującego wyrażenia: Sowoce['żółty'];
// jest równe 'banan1
Na koniec utwórzmy pustą tablicę, wywołując funkcję array ( ) bez parametrów: 5pusta_tablica = a r r a y ( ) ;
Może to być przydatne w przypadku funkcji, które spodziewają się tablicy jako argumentu. Mimo że używamy konstrukcji array o do tworzenia prostych tablic, można za jej pomocą tworzyć również tablice wielowymiarowe (opiszemy je w następnej części rozdziału).
Funkcje zwracające tablice Ostatnim sposobem tworzenia tablic jest wywołanie funkcji zwracającej tablicę (funkcja zdefiniowana przez użytkownika, w której tablica zostanie stworzona za pomocą jednej z opisanych metod, lub jedna z funkcji wbudowanych, które tworzą tablice wewnętrznymi mechanizmami PHP). Wiele funkcji związanych z bazami danych zwraca wynik w postaci na bieżąco tworzonej tablicy. Inne funkcje, tworzące tablice, są wygodnymi narzędziami dla innych funkcji operujących na tablicach. Jedną z nich jest funkcja rangę ( ) , która pobiera dwie liczby i zwraca tablicę zawierającą te liczby oraz wartości spomiędzy nich: $tablica = r a n g ę ( 1 , 5 ) ;
Powyższy wiersz jest równoznaczny: S t a b l i c a = a r r a y ! l, 2 , 3, 4 , 5 ) ;
Odczytywanie wartości Po zapisaniu wartości do tablicy musimy poznać sposób jej odczytania.
Rozdział 11. » Tablice i funkcje operujące na tablicach_____________________205
Odczytywanie przy użyciu indeksu Bezpośrednią metodą odczytania wartości jest użycie jej indeksu. Jeżeli wartość została zapisana w tablicy $tablica pod indeksem 5, wyrażenie $tablica [5] powinno mieć jej wartość. Jeżeli zmienna $tablica nie została zainicjowana lub nic nie zostało zapisane pod indeksem 5, $tablica[5] będzie się zachowywała jak niezainicjowana
zmienna.
Konstrukcja list() Istnieje kilka sposobów odczytania wartości z tablicy bez korzystania z kluczy. Większość z nich wykorzystuje to, że tablice pamiętają porządek, w jakim były zapisywane elementy. Opiszemy to dokładniej w części „Iteracje". Tu zamieścimy przykład użycia
konstrukcji list (), która może być używana do przypisywania kilku kolejnych elementów tablicy do zmiennych. Wykonajmy następujące dwa wiersze kodu: $owoce = array('jabłko', 'pomarańcza1, 'banan'); list($owoc_czerw, $owoc_pom) = $owoce;
Wynikiem wykonania tego fragmentu kodu będzie przypisanie do zmiennej $owoc_ 1
czerw ciągu ' j a b ł k o i ciągu 'pomarańcza' do zmiennej $owoc_pom. Ciąg ' b a n a n
1
nie zostanie przypisany zmiennej, ponieważ nie dostarczyliśmy odpowiedniej liczby
zmiennych. Zmienne będące argumentami list () są kojarzone z elementami według kolejności ich zapisywania w tablicy. Zauważmy niecodzienny element składni: konstrukcja list () jest po lewej stronie operatora przypisania, gdzie normalnie znajdują się tylko zmienne. W pewnym sensie l i s t o jest przeciwieństwem lub odwrotnością a r r a y ( ) , która umieszcza wartości swoich argumentów w tablicy, l i s t o dzieli tablicę na indywidualne zmienne. Wykonajmy następujący wiersz kodu: list($pierwszy, 5drugi) = array(Spierwszy, Sdrugi);
Powoduje to przypisanie wartości $pierwszy i $drugi do tych samych zmiennych, po tymczasowym zapisaniu do tablicy. Konsekwentnie nazywaliśmy array o i listo konstrukcjami, a nie funkcjami, ponieważ nie są to funkcje. Są to słowa kluczowe realizujące funkcje języka (jak if, while, function itp.), są interpretowane przez język, a nie poprzez zwykłą procedurę odczytywania parametrów wywołania funkcji. Pamiętaj, że wartości argumentu funkcji są obliczane przed jej wykonaniem, więc konstrukcje takie wymagają specjalnej interpretacji. Trzeba prześledzić przykłady użycia zarówno array o, jak i listo, aby zrozumieć, dlaczego potraktowanie ich jak wywołania funkcji może prowadzić do niespodziewanych wyników.
Tablice wielowymiarowe Do tej pory zajmowaliśmy się tylko tablicami jednowymiarowymi, z jednym poziomem kluczy w nawiasach kwadratowych. Jednak PHP potrafi obsługiwać tablice wielowymiarowe z dowolną liczbą kluczy. Pierwsze odwołanie do tablicy może być przypisa-
Jest to tablica pięciowymiarowa, z indeksami będącymi liczbami całkowitymi. Pamiętaj, że wartości zapisane w tablicy mogą być tablicą, liczbami lub ciągami znaków. Wielowymiarowa składnia z poprzedniego przykładu może być zwięzłą formą
odwołania do (czterowymiarowej) tablicy, połączonej z kluczem o wartości l, która to
tablica zawiera tablicę (trójwymiarową) itd. Zauważ, że w takiej strukturze mogą istnieć
różne poziomy zagłębienia:
5tablica_wielowym[0] = "prosty ciąg"; $ tablica_wielowym [ l ][' zawiera '] = "głębiej zapisany ciąg";
Klucz o wartości O przechowuje ciąg znaków, klucz o wartości l — tablicę zawierającą kolejny ciąg. Nie możesz jednak wykonać poniższego przypisania bez utraty wartości pierwszego przypisania: "prosty ciąg". Klucz O może być użyty do przechowania
Jeżeli będziesz pamiętać, że tablice wielowymiarowe to zwykłe tablice zawierające kolejne tablice, łatwo zrozumieć, w jaki sposób konstrukcja array ( ) uogólnia tworzenie tablic. To pozornie skomplikowane przypisanie jest w gruncie rzeczy bardzo proste: $tablica = array!'owoc' => array( czerwony1 => 'jabłko', pomarańczowy' => 'pomarańcza',
'kwiat
żółty' => 'banan', zielony' => 'gruszka'),
=>
array( czerwony' => 'róża',
żółty' => 'słonecznik', fioletowy' => 'irys'));
Jest to prosta tablica zawierające dwa elementy, zapamiętane wraz z ich wartościami klucza; każdy z nich jest tablicą. Po utworzeniu tej tablicy można się do niej odwołać w następujący sposób: $rodzaj = 'kwiat'; $ kolor = 'fioletowy';
print("$kolor Srodzaj to". S tablica[Srodzaj ] [$kolor));
Po wykonaniu tego fragmentu w oknie przeglądarki zobaczymy: fioletowy kwiat to irys
Rozdział 11. » Tablice i funkcje operujące na tablicach_______________________207
^^ \A
W powyższym przykładzie użyliśmy operatora konkatenacji ciągów, zamiast wbudowania odwołania $tabiica [ $ r o d z a j ] [$koior] do drukowanego ciągu. Powodem takiego działania jest to, że PHP 3 może nieprawidłowo zanalizować wielokrotne indeksy w ciągu, więc trzeba to wyrażenie dołączyć do ciągu za pomocą operatora. PHP 4 obsługuje to w lepszy sposób — możesz bezpiecznie wbudowywać tego typu wyrażenia w ciągi, jeżeli otoczysz je nawiasami klamrowymi: print("Skolor Srodzaj to ($tablica[$rodzaj][Skolor)(");
Zauważmy, że konsekwencje pomyłki w indeksowaniu tablic wielowymiarowych, podczas odczytywania informacji, nie są duże. Jeżeli nie ma odpowiedniego klucza, wyrażenie będzie traktowane jak zmienna niezainicjowana. Jeżeli spróbujesz wykonać następujące wiersze: Srodzaj = 'owoc';
Skolor = 'fioletowy 1 ; // ratunku, nie zapisaliśmy ani jednej śliwki! print("$kolor Srodzaj to ". $tablica[$rodzaj][$kolor]);
w wyniku otrzymasz: fioletowy owoc to
Informacje o tablicach Potrafimy już tworzyć tablice, zapisywać w nich wartości oraz odczytywać je. W tabeli 11.1 zebraliśmy kilka funkcji pozwalających otrzymać informacje na temat tablic. Tabela 11.1.
Proste funkcje zwracające informacje o tablicach Funkcja
Opis
is_array ( )
count ( )
Pobiera jeden argument dowolnego typu i zwraca wartość TRUE, jeżeli argument jest tablica, a w przeciwnym wypadku zwraca FALSE
Pobiera jako argument tablicę i zwraca liczbę pełnych elementów tablicy (dla ciągów i liczb będzie to 1)
sizeof o
Identycznie jak count()
in_array ( )
Pobiera dwa argumenty: element (który może znajdować się w tablicy) oraz tablicę (która
może zawierać element). Zwraca TRUE, jeżeli element zawiera się w tablicy
Usuwanie z tablicy Usunięcie elementu z tablicy jest analogiczne do usuwania zmiennej. Po prostu wywołaj funkcję unset ( ) , np.:
Zakładając, że zmienna $tablica była niezainicjowana, po wykonaniu tego fragmentu otrzymamy tablicę zawierającą dwa elementy ('potrzebny', 'znowu potrzebny') połączone z kluczami O i 2. Element ' niepotrzebny' został usunięty z tablicy. Zauważ, że operacja ta nie jest równoważna przypisaniu do wartości pustej. Jeżeli zamiast wywołania funkcji unset ( ) wykonamy następujący wiersz: Stablicall] = ' ' ;
otrzymamy tablicę zawierającą trzy elementy (' potrzebny', ' ', ' znowu potrzebny') połączone z kluczami O, l i 2.
Iteracje Oprócz zapisywania wartości połączonych 7 kluczami, tablice PHP budują uporządkowaną w kolejności tworzenia listę par klucz i wartość. Wspierają w ten sposób operację przeglądania całej zawartości tablicy (iteracji). Trudno jest zbudować zwykłą pętlę na
bazie rosnącego indeksu, ponieważ indeksy tablicy nie muszą być liczbami.
W tablicach występuje ukryty mechanizm systemu wskaźników. Każda z zapisanych par klucz i wartość wskazuje kolejną parę. Jednym z efektów dodania pierwszego elementu do tablicy jest ustawienie wskaźnika elementu bieżącego na pierwszy element tablicy. Wskaźnik ten pozostaje, chyba że zostanie przesunięty przez jedną z funkcji iteracyjnych. System list dynamicznych jest alternatywnym sposobem przeglądania i manipulowania
tablicą do systemu zapisywania i odczytywania na podstawie kluczy. Rysunek 1 1 . 1 zawiera ogólny schemat tych systemów w tablicach (nie oddaje dokładnie prawdziwej
implementacji). ^^> \A
Każda tablica pamięta, która z par klucz i wartość jest „bieżąca", a funkcje iteracyjne przesuwają znacznik bieżącego elementu po wewnętrznej liście kluczy i wartości. Mimo że nazywamy ten znacznik „wskaźnikiem bieżącym", PHP nie zawiera wskaźników w sensie C i C++; określenie to występuje tylko w kontekście iteracji po tablicy.
Użycie funkcji iteracyjnych Aby prześledzić działanie funkcji iteracyjnych, utworzymy przykładową tablicę używa-
ną w kolejnych przykładach.
Rozdział 11. * Tablice i funkcje operujące na tablicach_______________________209
W tablicy tej zapisaliśmy kilka nazw miast połączonych z indeksami numerycznymi. Zapamiętaliśmy również w tej tablicy nazwy krajów, indeksując je nazwami miast. Można to wykonać jedną instrukcją array ( ) , ale rozbicie na pojedyncze przypisania powoduje, że struktura tablicy jest lepiej widoczna.
Teraz odczytamy dane zawarte w tej tablicy, używając systemu kluczy. Jeżeli przyj-
miemy konwencję opisaną w powyższym przykładzie (miasta zapisane z indeksami
numerycznymi, kraje indeksowane nazwą miasta), możemy napisać funkcję wypisującą miasto i związany z nim kraj. function city_by_number ($number__index, $city_array) ( if (IsSet($city_array[$number_index]))
Sthe_city = $city_array[$number_index]; $the_country = Scity_array[?the_city]; print("$the_city to miasto w kraju $the_country "); }
Jeżeli zawartość tablicy jest identyczna jak w poprzednim fragmencie kodu, w przeglądarce powinieneś zobaczyć: Caracas to miasto w kraju Wenezuela Paryż to miasto w kraju Francja Tokio to miasto w kraju Japonia
Taka metoda odczytywania działa doskonale, jeżeli znamy strukturę zapisanych w tabeli danych i wszystkie klucze. Co zrobić, aby wypisać całą zawartość tablicy? Nie ma dobrej metody sprawdzenia wszystkich możliwych kluczy. Jeżeliby istniała metoda, byłaby nieefektywna.
Iteracje za pomocą current() i next() Za pomocą funkcji iteracyjnych current ( ) i next ( ) można wypisać całą zawartość tablicy. Zwróć uwagę, że wywołanie funkcji jest powtórzone. function print_all_array(Scity_array) { // Uwaga! Nie działa najlepiej. Sprawdź funkcję each() $current_item = current($city_array); if ($current_item) print("$current_item ") ; else print("Nie ma nic do wypisania ");
while ($current_item = next($city_array)) print("$current_itera ") ; )
Funkcja current ( ) zwraca wartość znacznika bieżącego elementu (na rysunku 11.1 pokazano schemat wewnętrznej budowy tablic). Jeśli tablica jest tworzona za pomocą przypisania jej elementu, element będzie wskazywany jako bieżący. Funkcja n e x t ( ) przesuwa ten wskaźnik i zwraca wartość bieżącego elementu. Jeżeli funkcja n e x t ( ) zostanie wywołana, gdy bieżący wskaźnik znajduje się na ostatnim elemencie tablicy, zwróci wartość FALSE. "<3
f^ilfcfe LjggSjl' •^"•
W ostatnim przykładzie znajduje się pułapka (nie widać jej w tym przypadku) obniżająca wiarygodność tej metody poszukiwania elementów w tablicy. Jeżeli w tablicy mamy zapisane wartości FALSE, nasza pętla while nie będzie ich potrafiła odróżnić od wartości FALSE, którą next o zwraca przy wyczerpaniu się elementów tablicy. Rozwiązaniem tego problemu jest użycie funkcji each ( ) , która zostanie opisana w dalszej części tego rozdziału.
Wykonanie poprzedniego fragmentu kodu spowoduje wypisanie w przeglądarce następującej listy: Caracas Wenezuela Paryż
Francja Tokio
Rozdział 11. » Tablice i funkcje operujące na tablicach_______________________211 Japonia Caracas Wenezuela Paryż Francja
Tokio
Japonia
To wszystkie elementy tablicy w kolejności ich zapisywania (powtórzone, ponieważ wywołaliśmy funkcję dwukrotnie).
W jaki sposób otrzymaliśmy te same wyniki przy drugim wywołaniu funkcji print_ all_array ( ) ? W jaki sposób wskaźnik bieżącego elementu wrócił na początek, aby za drugim razem funkcja znów przejrzała wszystkie elementy? Odpowiedź jest związana z faktem, że przekazywanie argumentów do funkcji jest realizowane poprzez wartość, a nie argument. Oba wywołania funkcji pobieraj ą nową kopię tablicy, na której funkcja next ( ) nie była wykonywana. ^f—^
Więcej na temat kopiowania argumentów przez funkcję w rozdziale 8.
Ue _____________________________ Możemy sprawdzić to wyjaśnienie, przekazując do funkcji tablicę poprzez referencję, a nie przez wartość. Jeżeli zdefiniujemy tę samą funkcję, ale wywołamy ją za pomocą
otrzymamy w wyniku następujący wynik: Caracas Wenezuela Paryż Francj a
Tokio Japonia Nie ma nic do wypisania
Tym razem wskaźnik bieżącego elementu globalnej wersji tablicy został przesunięty przez pierwsze wywołanie funkcji. ^^> ^^
Większość funkcji iteracyjnych posiada wartość i efekt uboczny. W przypadku funkcji next o, p r e v o , reset o oraz end o efektem ubocznym jest zmiana położenia wewnętrznego wskaźnika; zwracana jest wartość pary klucz i wartość bieżącego elementu po zmianie położenia wskaźnika
Powtórne przeglądanie za pomocą reset() W poprzedniej części napisaliśmy funkcję wypisującą wszystkie wartości elementów tablicy, która nie działa w przypadku, gdy wskaźnik bieżącego elementu tablicy nie znajduje się na początku listy elementów tablicy. Funkcja reset () pozwala przesunąć
ten wskaźnik na początek. Ustawia wskaźnik na pierwszy element i zwraca jego wartość. Możemy użyć tej funkcji, aby ulepszyć działanie naszej funkcji drukującej, zamieniając wywołanie funkcji current () na reset (). function print_all_array_reset($city_array) ( // Uwaga! Nadal nie najlepiej. Sprawdź funkcje each() $current_item = reset($city_array); // przesuwa i zwraca wartość if ($current_item) print("$current_item ");
else print("Nie ma nic do wypisania "); while ($current_item = next(Scity_array)) print("$current_item "); )
Funkcja zawsze rozpoczyna od pierwszego elementu, bez względu na położenie wskaźnika bieżącego elementu. Warto uzależnić od sposobu przekazywania argumentu. Użycie funkcji reset () może wydać się niejasne. Można zamienić pierwszy wiersz ciała funkcji na dwa następujące: reset($city_array);
// przesunięcie na pierwszy element
$current_item = current($city_array); // wartość pierwszego el.
Wypisywanie w odwrotnym porządku za pomocą end() i prev() Poznaliśmy już funkcje next () (przesuwająca wskaźnik do przodu) oraz reset () (przesuwająca na początek). Analogicznie działają funkcje prev ( ) (przesuwająca wskaźnik wstecz) oraz end ( ) (przesuwająca wskaźnik na ostatni element w liście). Możemy ich użyć, aby wypisać zawartość tablicy w odwrotnym porządku. function print_all_array_backward($city_array) { // Uwaga! Nadal nie najlepiej. Sprawdź funkcję each()
$current_item = end($city_array); // przewija na koniec if ($current_item) print ( "$current_item ") ; else print("Nie ma nic do wypisania ");
while ($current_item = prev($city_array)) print("$current_item "); )
print_all_array_backward(Sstolica) ;
Jeżeli wywołamy tę funkcję z taką samą, jak w poprzednich przykładach, zawartością tablicy $stolica, otrzymamy te same wyniki w odwrotnym porządku: Japonia Tokio Francja Paryż
Wenezuela Caracas
Rozdział 11. » Tablice i funkcje operujące na tablicach_______________________213
Pobieranie wartości kluczy za pomocą key() Do tej pory drukowaliśmy tylko wartości zapisane w tablicy, mimo że zapisywaliśmy również klucze. Wartości kluczy z wewnętrznej listy można pobrać używając funkcji
key ( ) , która działa analogicznie do current ( ) , ale zwraca klucz, a nie wartość (patrz
rysunek 11.1). Aby użyć funkcji key O , zmodyfikujemy jedną z naszych wcześniejszych funkcji, żeby wypisywała zarówno klucze, jak i wartości. function print_keys_and_values(Scity_array) ( // Uwaga! Przeczytaj opis funkcji each() reset{$city_array);
$current_item = current(Scity_array); $current_key = key($city_array) ; if ($current_item) print("Klucz: $current_key; Wartość: $current_item "); else print("Nie ma nic do wypisania "); while ($current_itern = next($city_array)) (
Wartości puste i funkcja each() Napisaliśmy kilka funkcji drukujących zawartość tablicy, ale każda z nich ma tę samą
słabość. Każda z nich kontroluje warunek zakończenia poprzez sprawdzenie, czy funkcja next () zwraca wartość FALSE. Zdarza się to, gdy zostaną wyczerpane wszystkie elementy tablicy. Może się zdarzyć, jeżeli napotkamy zapisaną w tablicy wartość FAL-
SE. Wartością FALSE może być pusty ciąg, liczba O lub wartość logiczna FALSE. Każda z tych wartości może zostać zapisana w tablicy jako prawidłowa wartość wykorzystywana do pewnych zadań. Na ratunek przychodzi nam funkcja each ( ) , która jest nieco podobna do next ( ) , ale zwraca wartość FALSE jedynie wtedy, gdy zabraknie elementów tablicy. Funkcja each () dodatkowo zwraca tablicę zawierającą zarówno wartość klucza, jak i wartość elementu. Utrudnia to opisywanie tej funkcji, ponieważ trzeba rozróżnić dwie tablice: tablicę, któ-
rą przeglądamy, i tę, którą each ( ) zwraca za każdym wywołaniem. Zwracana tablica ma cztery pary wartości klucz i wartość: * klucz: O, wartość: bieżący klucz; •* klucz: l, wartość: bieżąca wartość;
214___________________________________________Część l
»
Podstawy PHP
* klucz: ' k e y ' , wartość: bieżący klucz; * klucz: ' value ', wartość: bieżąca wartość.
Bieżący klucz i bieżąca wartość to klucz i wartość bieżącego elementu przeglądanej tablicy. Inaczej mówiąc, zwracana wartość jest paczką zawierającą parę klucz i wartość z przeglądanej tablicy (oferuje indeksy numeryczne oraz będące ciągami). Oprócz różnych typów zwracanych wartości, funkcja each o różni się od funkcji next ( ) tym, że each ( ) zwraca wartość przed przesunięciem wskaźnika bieżącego elementu, natomiast next o zwraca wartość po przesunięciu elementu. Oznacza to, że jeżeli wskaźnik bieżącego elementu będzie na początku tablicy, kolejne wywołania funkcji each o zwrócą wszystkie wartości zapisane w tablicy, a takie same wywołania funkcji next o ominą pierwszy element.
Użyjmy funkcji each ( ) , aby napisać lepszą wersję funkcji wypisującej wartości kluczy i wartości zapisane w tablicy:
function print_keys_and_values_each($city_array) ( // Skutecznie wypisuje całą zawartość tablicy
reset($city_array); while ($array_cell = each($city_array)) (
Wynik ten jest identyczny z wynikiem działania poprzedniej funkcji print_keys_ and_values ( ) . Różnica polega na tym, że nowa funkcja nie zatrzyma się wcześnie,
jeżeli napotka pustą wartość lub wartość FALSE.
Przeglądanie tablicy za pomocą array_walk() Ostatnia funkcja iteracyjna pozwala przekazać dowolną funkcję napisaną przez użytkownika do wykonania na elementach tablicy. Funkcja taka może wykonać dowolne czynności na parze klucz i wartość. Funkcja array_walk ( ) wymaga dwóch argumen-
tów: tablicy do przeglądania i nazwy funkcji wykonywanej dla każdego elementu (posiada również trzeci opcjonalny argument, który opiszemy później).
Rozdział 11. » Tablice i funkcje operujące na tablicach_______________________215
Funkcja przekazana do a r r a y _ w a l k ( ) powinna posiadać dwa lub trzy argumenty. Pierwszy element jest wartością komórki tablicy, a drugi jej kluczem. Poniższa funkcja drukuje ciąg informujący o długości ciągu zapisanego w tablicy: function print_value_length($array_value, $array_key) { $the_length = strlen($array_value);
print("Ciąg $array_value ma długość: Sthe_length ");
)
Funkcja ta nie korzysta z drugiego argumentu. Użyjmy teraz tej funkcji do naszej standardowej tablicy z wykorzystaniem funkcji a r r a y _ w a l k ( ) : array_walk(Sstolica, 'print_value_length');
W efekcie zobaczymy: Ciąg Ciąg Ciąg Ciąg Ciąg Ciąg
Caracas ma długość: 7 Wenezuela ma długość: 9 Paryż ma długość: 5 Francja ma długość: 7 Tokio ma długość: 5 Japonia ma długość: 7
Funkcja array_walk() posiada trzeci, opcjonalny argument, który, przekazywany jest do trzeciego argumentu funkcji definiowanej przez użytkownika. Argument ten jest identyczny dla wszystkich elementów tablicy, ale pozwala na dodatkowe sterowanie funkcją. W tabeli 11.2 zamieszczone jest podsumowanie działania wszystkich funkcji iteracyjnych opisanych w tym rozdziale.
Stosy i kolejki Stosy i kolejki są abstrakcyjnymi strukturami danych, często używanymi w teorii informatyki. Zapewniają odpowiednią dyscyplinę w dostępie do przechowywanych elementów. Jak wcześniej wspomnieliśmy, tablice PHP pozwalają na imitację innych struktur danych. Niezależność tablic od typu zapisywanych danych pozwala łatwo implementować stosy i kolejki. PHP zawiera kilka funkcji przeznaczonych do tego celu. Jeżeli będziesz używał tylko tych funkcji, możesz zapomnieć, że bazują na tablicach. Stos jest kontenerem zapamiętującym wartości, zapewniającym tryb dostępu do danych LIFO (ang. last in-first out — ostatni wchodzi, pierwszy wychodzi). Oznacza to, że stos zapamiętuje kolejność zapisu elementów, a jedynym sposobem otrzymania wartości elementu jest pobranie (i usunięcie) ostatnio zapisanej wartości. Zwykle porównuje się tę strukturę do stosu tac w kawiarni w jednym z zasobników, utrzymujących stały poziom górnej tacy. Można dodać nowe tace do stosu starych i można zabrać tace z góry, ale nie da się wyjąć starej tacy bez wyjęcia nowych. Czynność dodawania do stosu nazywana jest „położeniem" wartości na stos, a czynność uzyskania wartości z góry jest nazywana „zdjęciem" ze stosu. Inną analogią jest sposób, w jaki niektóre przeglądarki zapamiętują odwiedzone strony, aby można było wrócić do nich za pomocą przycisku Wstecz. Przejście do nowej strony powoduje położenie nowego adresu na stos, a użycie przycisku Wstecz zdejmuje adres ze stosu.
216_________________________________________Część
l
»
Podstawy
PHP
Tabela 11.2.
Funkcje iteracyjne
Funkcja
Argumenty
Efekt uboczny
current ()
Jeden argument: tablica
Brak
Jeden argument: tablica
Przesuwa wskaźnik bieżącego elementu do
Wartość bieżącego elementu po jego przesunięciu (lub
ostatnim elemencie, kolejne
elementów)
next ( )
Zwracana wartość Wartość bieżącego elementu
tablicy lub FALSE, jeżeli nie ma już elementów
przodu. Jeżeli znajduje się na FALSE, jeżeli nie ma już
wywołania zwracają FALSE prev ( )
Jeden argument: tablica
Przesuwa wskaźnik wstecz o jeden. Jeżeli znajduje się na pierwszym elemencie,
przesuwa wskaźnik „przed początek"
Wartość bieżącego elementu po jego przesunięciu (lub FALSE, jeżeli nie ma już
elementów)
reset ( )
Jeden argument: tablica
Przesuwa wskaźnik na pierwszy element lub „przed początek", jeżeli tablica jest pusta
Wartość pierwszego elementu lub FALSE, jeżeli tablica jest pusta
end()
Jeden argument: tablica
Przesuwa wskaźnik na
Wartość ostatniego elementu tablicy
Brak (funkcja identyczna z current ( ) )
Wartość bieżącego elementu tablicy lub FALSE, jeżeli nie ma już elementów
Przesuwa wskaźnik do następnego elementu
Tablica zawierająca wartość i klucz elementu
pos ()
Jeden argument: tablica
each()
Jeden argument: tablica
ostatni element
wskazywanego przed przesunięciem wskaźnika
(lub FALSE, jeżeli nie ma już elementów). Zwracana
tablica przechowuje wartości pod indeksami 0 i 1 oraz 'key' i 'value'
array walk ( )
1 . Tablica 2. Nazwa dwuargumentowej (lub trójargumentowej)
funkcji wywoływanej dla każdego elementu 3. Opcjonalny argument
Funkcja wywołuje funkcję Zwraca 1 o nazwie przekazanej przez jej
drugi argument dla każdego elementu tablicy. Efekt
uboczny zależy od efektu ubocznego realizowanego przez przekazaną funkcję
Kolejka jest podobna do stosu, ale dostęp do danych jest organizowany na zasadzie FIFO (ang. First in-First out — pierwszy wchodzi, pierwszy wychodzi). Zwykle porównuje się tę strukturę z kolejką osób. Ten, kto czeka dłużej w kolejce, będzie obsłużony w następnej kolejności.
Rozdział 11. » Tablice i funkcje operujące na tablicach_____________________217
Funkcje obsługi stosu to array_push ( ) i array_pop ( ) . Funkcja array_push ( ) oczekuje nazwy tablicy jako pierwszego argumentu, następnie dowolnej liczby elementów do położenia na stos. Elementy będą wstawiane w kolejności od lewej do prawej. Funk-
cja array_pop ( ) wymaga podania tablicy i zdejmuje element ze szczytu stosu, zwracając go jako wartość. Rozważmy następujący fragment: Sstos = arrayO; // wymagany - array_push() nie stworzy tablicy array_push(Sstos, "pierwszy", "środkowy"); array_push(?stos, "ostatni"}; while ($pobrany = array_pop(Sstos)) print("Zdejmujemy ze stosu i mamy: $pobrany ");
W efekcie otrzymamy: Zdejmujemy ze stosu i mamy: ostatni Zdejmujemy ze stosu i mamy: środkowy Zdejmujemy ze stosu i mamy: pierwszy
PHP 4 posiada również funkcje działające w ten sam sposób, co array_push ( ) i ar-
ray_pop ( ) , ale na drugim końcu tablicy (dodają i usuwają elementy z początku tablicy). Funkcja array_unshif t ( ) jest analogiczna do array_push ( ) , a r r a y _ s h i f t ( )
działa podobnie do array_pop ( ) . Jeżeli weźmiemy jedną z funkcji z kolumny A i jedną z kolumny B, otrzymamy obsługę kolejki. Zmodyfikujmy nasz poprzedni przykład,
aby położyć elementy na początek tablicy (za pomocą array_unshift ( ) ) i zdjąć je z końca (za pomocą array_pop ( ) ) : $kolejka = arrayO; // wymagany - array_unshif t () nie stworzy tablicy array_unshift($kolejka, "pierwszy", "środkowy"); array_unshift(Skolejka, "ostatni"); while ($pobrany = array_pop($kolejka)) print{"Zdejmujemy ze stosu i mamy: $pobrany ");
Fragment ten daje następujący wynik: Z d e j m u j e m y ze stosu i mamy: pierwszy Zdejmujemy ze stosu i mamy: środkowy
Z d e j m u j e m y ze stosu i mamy: ostatni ^
f^-li^fe
Q^4Jr
Funkcje a r r a y _ u n s h i f t O i a r r a y _ s h i f t () różnią się od a r r a y _
pusho iarray_pop() tym, że przenumerowują tablicę, jeżeli indeksy są liczbami całkowitymi. Niektórzy użytkownicy używają indeksów numerycznych, aby uporządkować zawartość tablicy. Użycie array_unshifto do wstawienia wartości na początek tablicy powinno przypisać indeks O nowemu elementowi i zmienić numerację pozostałych. Pobranie elementu z początku za pomocą funkcji array_shifto powoduje zmniejszenie wartości klucza o jeden w pozostałych elementach (nie zachodzi to W przypadku array_push() i a r r a y _ p o p ( ) ,
ponieważ działają one na końcu tablicy, więc renumeracja nie jest potrzebna). Jeżeli używasz ciągów jako indeksów, funkcje nie zmienią ich wartości. Zdarza się to często w funkcjach PHP operujących na tablicach: niektóre z nich traktują indeksy jak inne indeksy asocjacyjne; niektóre zakładają, że liczby te oznaczają porządek w tablicy i zmieniają je w razie potrzeby.
218_________________________________________Część l
»
Podstawy PHP
Funkcje realizujące stos i kolejkę zebrane są w tabeli 11.3. Tabela 11.3.
Funkcje stosu i kolejki Funkcja
Argumenty
Efekt uboczny
Zwracana wartość
array_push()
Pierwszy argument to tablica, następnie
Dodaje elementy na koniec tablicy
Lic/.ba elementów w tablicy po wstawieniu
Usuwa element z końca tablicy
Zwraca ostatni (usunięty) element lub wartość FALSE, jeżeli tablica jest pusta
dowolna liczba wartości
nowych
array_pop()
Jeden argument: tablica
array_unshif t O
Pierwszy argument to Dodaje elementy na początek Liczba elementów tablica, następnie tablicy (ostatni argument w tablicy po wstawieniu dowolna liczba wartości będzie pierwszym elementem nowych tablicy)
array_shift
()
Jeden argument: tablica
Usuwa element z początku
tablicy
Zwraca pierwszy
(usunięty) element lub wartość FALSE, jeżeli tablica jest pusta
Przekształcenia tablic PHP 4 posiada wiele funkcji manipulujących danymi zawartymi w tablicy. Wszystkie funkcje przedstawione w tej części wykonuj ą określone czynności na tablicy i zwracają wynik
w postaci innej tablicy (funkcje sortujące tablice zostały wydzielone w osobnej części).
W tym rozdziale ulepszaliśmy funkcję drukującą całą zawartość tablicy; w tej części
użyjemy ostatniej wersji (print_keys_and_values_each ( ) ) do pokazania zawartości tablicy zwracanej przez opisywane funkcje.
Pobieranie kluczy i wartości Funkcja array_keys ( ) zwraca klucze z tablicy, przekazanej jako argument, jako nową tablicę, w które są zapisane jako wartości. Kluczami nowej tablicy są zwykle kolejne liczby począwszy od zera. Funkcja array_values ( ) robi dokładnie to samo z wartościami zapisanymi w tablicy.
Tablice i funkcje operujące na tablicach_______________________219
Teraz wypiszemy zawartość tablic będących wynikiem działania tych dwóch funkcji: print("Klucze tablicy: "); print_keys_and_values_each( array_keys($pizza_requests)); print("Wartości tablicy: "); print_keys_and_values_each( array_values($pizza_requests));
W wyniku otrzymamy: Klucze tablicy: Klucz 0; Wartość Alice Klucz 1; Wartość Bob Klucz 2; Wartość Carl Klucz 3; Wartość Dennis Wartości tablicy: Klucz
0; Wartość
pepperoni
Klucz Klucz
2; Wartość 3; Wartość
kiełbasa grzyby
Klucz
1; Wartość
grzyby
Druga z funkcji (array_values ( ) ) nie wydaje się interesująca, ponieważ na podsta-
wie starej tablicy otrzymujemy po prostu nową tablicę z kluczami zamienionymi na kolejne liczby.
Możemy zrobić coś bardziej użytecznego (i przydatnego w porządkowaniu) za pomocą funkcji array_count_values ( ) . Funkcja ta pobiera tablicę i zwraca nową, w której stare wartości są kluczami, a wartością — liczba wystąpień tej wartości w oryginalnej
W wyniku otrzymujemy: Klucz: pepperoni; Wartość: l Klucz: grzyby; Wartość: 2 Klucz: kiełbasa; Wartość: l
Zamiana, odwracanie i mieszanie Jeszcze dziwniejszą funkcją jest array_f lip { ) , która zamienia klucze tabeli na wartości, i na odwrót. Dla przykładu: print_keys_and_values_each(array_flip($pizza_requests));
co daje: Klucz: pepperoni; Wartość: Alice Klucz: grzyby; Wartość: Dennis // co stało się z Bobem? Klucz: kiełbasa; Wartość: Carl
Należy zapamiętać, że w tablica gwarantuje unikalność kluczy, a wartości mogą się powtarzać. Z tego powodu wszystkie powtarzające się wartości z oryginalnej tablicy stają się kluczem w nowej. Tylko jeden z oryginalnych kluczy pozostaje nową wartością. Odwrócenie tablicy jest proste: array_reverse ( ) zwraca nową tablicę z elementami
w odwrotnym porządku. Użyjmy naszej funkcji testującej:
Mimo że został zmieniony wewnętrzny porządek tablicy, wszystkie pary klucz i wartość pozostały takie same. Jednak funkcja ta (jak kilka innych PHP) traktuje indeksy numeryczne w specjalny sposób. Zakłada, że porządek kluczy powinien zostać również odwrócony, aby można było użyć kodu pobierającego porządek elementów z indeksów, zamiast porządku wewnętrznej listy. Funkcja array__reverse ( ) zamienia kolejność kluczy numerycznych, aby nowy porządek kluczy odpowiadał porządkowi listy wewnętrznej. Funkcja shuffle ( ) pobiera tablicę jako argument i zmienia w losowy sposób porządek
elementów tablicy. Używa funkcji randO (funkcja generująca kolejne liczby losowe), więc przed jej wywołaniem trzeba zainicjować generator liczb losowych za pomocą srand ( ) . Odpowiednia kolejność wywoływanych funkcji przedstawiona jest poniżej: s r a n d ( (double) m i c r o t i m e O * 1 0 0 0 0 0 0 ) ;
Kod ten może dać następujący wynik: Klucz: 0; Wartość: pepperoni Klucz: 1; Wartość: grzyby Klucz: 2; Wartość: kiełbasa Klucz: 3; Wartość: grzyby
Użyliśmy słowa „może", ponieważ nie można przewidzieć porządku. VoatfP tskZfi
"
Więcej na temat generowania liczb losowych w rozdziale 10. Jeżeli zarnierzasz użyć funkcji shuffle o, nie czytając rozdziału 10., na stronie używającej shuffle o wywołaj funkcję srand o (tylko raz), jak w przykładzie.
^ przeciwieństwie do wielu funkcji operujących na tablicach, funkcja shuffle o jest destrukcyjna. Operuje bezpośrednio na argumentach tablicy, zmieniając je, nie zwraca nowej tablicy. Oznacza to, że $nowa_tablice = shuffle($stara_tablica);
// ŹLE
jest niewłaściwym sposobem wywołania funkcji shuffle o , ponieważ funkcja shuffieo nie zwraca wartości. Właściwym sposobem wywołania jest: shuffle($tablica);
// zmienia tablicę
Powyższe funkcje, oraz kilka dodatkowych, zestawione sąw tabeli 11.4.
Rozdział 11.
»
Tablice i funkcje operujące na tablicach_______________________221
Tabela 11.4. Funkcje przekształcające tablice
Funkcja
Opis
a r r a y keys O
Posiada tablicę jako argument; zwraca nową tablicę zawierającą klucze z wejściowej tablicy; nowymi kluczami są liczby rozpoczynające się od zera
array values ( )
Posiada tablicę jako argument; zwraca nową tablicę zawierającą wartości z wejściowej tablicy; nowymi kluczami są liczby rozpoczynające się od zera
a r r a y count values ( )
Posiada tablicęjako argument; zwraca nową tablicę, w której kluczami są wartości ze starej tablicy; wartościąjest liczba wystąpień oryginalnej tablicy
array f l i p O
Posiada tablicęjako argument; zamienia klucze na wartości i odwrotnie
a r r a y reverse ( )
Posiada tablicęjako argument; zmienia wewnętrzny porządek elementów tablicy na odwrotny. Klucze numeryczne są przy tym przenumerowywane
shuffleO
Posiada tablicęjako argument; zmienia wewnętrzny porządek elementów tablicy na przypadkowy. Zmienia wartości kluczy numerycznych tak, aby pasowały do nowego uporządkowania. Funkcja korzysta z generatora liczb losowych rand ( ) ; przed wywołaniem shuffle ( ) musi zostać wywołana funkcja srand ()
a r r a y merge ( )
Dwie tablicęjako argumenty; zwraca tablicę będącą połączeniem obu tablic,
elementy pierwszej znajdują się na początku, następnie elementy drugiej.
Najbardziej użyteczne dla tablic używanych w charakterze list, ponieważ wartości powtarzających się kluczy zostaną nadpisane. Również klucze
numeryczne są przenumerowywane dla odzwierciedlenia nowego porządku
a r r a y pad ( )
Posiada trzy argumenty: wejściową tablicę, rozmiar wypełnienia i wartość wypełnienia. Zwraca nową tablicę wypełnioną według następujących zasad: jeżeli rozmiar wypełnienia jest większy od długości tablicy wejściowej, tablica jest wydłużana, za pomocą wartości wypełnienia, do rozmiaru wypełnienia dzięki kolejnym przypisaniom typu $tablica [ ] =$wart wypełnienia. Ujemna wartość rozmiaru wypełnienia powoduje działanie podobne, ale wypełnianie jest realizowane od początku tablicy, a nie od
końca. Jeżeli tablica ma długość większą od podanego rozmiaru wypełnienia
(w liczbach bezwzględnych), funkcja ta nie daje żadnego efektu array_slice ( )
Posiada trzy argumenty: tablicę wejściową, przesunięcie oraz opcjonalnie
długość. Zwraca nową tablicę, będącą wycinkiem wejściowej. Początek
i koniec wycinka określany jest przez przesunięcie i długość. Dodatnia wartość przesunięcia oznacza, że początek jest liczony od początku tablicy; wartość ujemna powoduje obliczenie punktu początkowego od końca tablicy. Opcjonalny argument długość określa, ile elementów będzie zawierać nowa
tablica (jeżeli jest to wartość dodatnia) lub na którym elemencie od końca się zakończy (w przypadku wartości ujemnej). Jeżeli argument ten nie zostanie podany, wycinek kończy się na końcu tablicy wejściowej array spliceO
Usuwa fragment tablicy i wstawia w to miejsce fragment pochodzący z innej. Posiada cztery argumenty: tablicę wejściową, przesunięcie, opcjonalnie długość i opcjonalnie tablicę zawierającą wartości do wstawienia. Zwraca
nową tablicę, zawierającą fragment wycięty z wejściowej. Zasady wyliczania początku i końca wycinka są identyczne jak w funkcji a r r a y slice ( ) . Jeżeli nie zostanie podana tablica do wstawienia, funkcja usuwa wycinek
tablicy wejściowej i zwraca go jako wartość. Jeżeli przekazana zostanie tablica do wstawienia, jej elementy zostaną wstawione w miejsce usuniętych
222_________________________________________Część
l
»
Podstawy
PHP
Zamiana pomiędzy tablicą i zmiennymi PHP 4 posiada kilka rzadko spotykanych funkcji, zamieniających pary klucz i wartość w tablicy na pary klucz i wartość zapisane w zwykłych zmiennych. Funkcja compact ( )
zamienia zmienne na tablicę, extract ( ) działa w przeciwnym kierunku. Funkcje te są opisane w tabeli 11.5. Tabela 11.5. Funkcje zamiany pomiędzy zmiennymi i tablicą Funkcja
Opis
compact ( )
Pobiera podany zbiór ciągów i analizuje go w poszukiwaniu nazw zmiennych; zwraca tablicę, w której kluczami są nazwy zmiennych, a wartościami — wartości tych zmiennych Funkcja przyjmuje dowolną liczbę argumentów, będących ciągami lub tablicami
zawierającymi ciągi na dowolnym poziomie zagłębienia. Zbiór ciągów przekazanych do funkcji jest analizowany w poszukiwaniu zmiennych. Ciągi niezawierające nazw zainicjowanych zmiennych są odrzucane
extract ( )
Jako argument posiada tablicę oraz dwa argumenty opcjonalne. Importuje pary klucz i wartość do środowiska wykonania skryptu. Klucze tablicy stają się nazwami zmiennych, a wartości z tablicy — wartościami zmiennych. Klucze, które nie są prawidłowymi nazwami
zmiennych, są ignorowane
Argumentami opcjonalnymi są: liczba całkowita (zawierająca jedną ze stałych) oraz ciąg zawierający przedrostek. Zadaniem tych argumentów jest obsłużenie kolizji istniejących zmiennych z zmiennymi tworzonymi na podstawie kluczy tablicy. Dozwolonymi stałymi dla
drugiego argumentu funkcji są: 1. EXTRJDVERWRITE; 2. EXTR_SKIP; 3.
EXTR_PREFIX_SAME oraz 4. EXTR__PREFIX_ALL. Dla tych czterech wartości funkcja działa
4. Użyj przedrostka dla wszystkich zmiennych tworzonych przez funkcję. Dla przykładu: e x t r a c t ( a r r a y ( ' z m i e n n a ' => 4 ) , E X T R _ P R E F I X _ S A M E , ' d i f f _ ' ) ; spowoduje
przypisanie do zmiennej Szmienna wartości 4, jeżeli $ zmienna nie była do tej pory użyta. W przeciwnym przypadku wartość 4 zostanie przypisana do $dif f__zmienna
Sortowanie Na koniec przedstawimy zestaw funkcji sortujących tablice. Jak wcześniej zauważyliśmy, często występuje rozdźwięk pomiędzy utrzymywaniem asocjacji pary klucz i wartość a traktowaniem kluczy numerycznych jako elementu porządkującego tablicę
(co skutkowało zmianą wartości kluczy w przypadku zmiany kolejności elementów w tablicy). Na szczęście PHP ma odpowiednie warianty funkcji sortujących, które pozwalają na wybór pomiędzy sortowaniem w porządku rosnącym i malejącym oraz zapewniają możliwość przekazania własnej funkcji porządkującej.
Rozdział 11.
»
Tablice i funkcje operujące na tablicach_______________________223
Nazwy tych funkcji są bardzo zwięzłe, każda litera (poza frazą ' s o r t ' ) ma własne znaczenie. Sposób ich rozszyfrowywania jest następujący: * początkowe ' a ' oznacza, że funkcja sortując wartości utrzymuje asocjacje pomiędzy kluczami i wartościami;
* początkowe ' k ' oznacza, że funkcja sortuje klucze utrzymując asocjacje; * brak początkowego ' a ' oraz ' k ' oznacza, że funkcja sortując wartości nie utrzymuje asocjacji pomiędzy kluczem i wartością. Numeryczne klucze zostają przenumerowane dla odzwierciedlenia nowego porządku elementów; ** litera ' r ' oznacza odwrotny porządek sortowania; + początkowe ' u ' oznacza, że funkcja spodziewa się w drugim argumencie na-
zwy funkcji, określającej porządek dowolnych dwóch sortowanych elementów (więcej informacji w tabeli 11.6).
Tabela 11.6.
Funkcje sortujące tablice Funkcja
Opis
asort ( )
Posiada jeden argument. Sortuje elementy według ich wartości, zachowując powiązanie pomiędzy kluczem i wartością. Dobra dla tablic asocjacyjnych
arsort ( )
Identycznie jak asort ( ) , ale sortuje w odwrotnym porządku
ksort ( )
Posiada jeden argument. Sortuje elementy według ich kluczy, zachowując powiązanie pomiędzy kluczem i wartością
krsort ( )
Identycznie jak krsort ( ) , ale sortuje w odwrotnym porządku
sort () rsort ( ) uasort ( )
Uksort ( ) usort ( )
Posiada jeden argument. Sortuje elementy według ich wartości. Klucze mogą zostać przenumerowane dla odzwierciedlenia nowego porządku wartości Identycznie jak rsort ( ) , ale sortuje w odwrotnym porządku Sortuje elementy używając funkcji porównującej. Jest podobna do asort ( ) , ale porządek elementów jest ustalany przez funkcję, której nazwa jest przekazana w drugim argumencie. Funkcja powinna zwracać wartość ujemną, jeżeli pierwszy element jest „przed" drugim, wartość dodatnią, jeżeli pierwszy element znajduje się „za" drugim, oraz zero, jeżeli elementy są takie same Identycznie jak uksort ( ) , ale sortuje w odwrotnym porządku Sortuje tablicę przy użyciu przekazanej funkcji porównującej. Podobna do uasort ( ) poza tym, że nie utrzymuje powiązania klucza z wartością (jak sort ())
Podsumowanie Tablica jest podstawowym typem PHP. Pozwala na emulację typu rekordowego oraz wektorów znanych z innych języków programowania. Tablice w PHP są asocjacyjne, co
224_________________________________________Część
l
»
Podstawy
PHP
oznacza, że przechowują wartości w połączeniu z unikalnymi kluczami bądź indeksami. Indeksy mogą być zarówno ciągami, jak i liczbami. Są umieszczane w nawiasach kwadratowych (wyrażenie $tablica [4 ] reprezentuje wartość zapamiętaną w tablicy $tablica związaną z indeksem 4; nie musi to być czwarty element tablicy). Z powodu ulotności typów do tablicy PHP można zapisać dowolną wartość. Oznacza to również, że tablice mogą występować jako elementy tablicy. „Tablice wielowymiarowe" to po prostu tablice zawierające tablice jako elementy. Do kolejnych poziomów
można się dostać za pomocą indeksów w kolejnych nawiasach (wyrażenie $ tablica [ 3 ] [ 4 ] odwołuje się do elementu tablicy — indeksowanego przez 4, który jest elementem tablicy $tablica — indeksowanym przez 3). Tablice są podstawą funkcji zwracających dane strukturalne, więc programiści PHP powinni nauczyć się rozpakowywać tablice, nawet jeżeli nie są zainteresowani ich tworzeniem. PHP dostarcza wielu funkcji manipulujących danymi zapisanymi w tablicach, np. funkcje zwracające liczbę, sumujące i sortujące.
Rozdział 12.
Przekazywanie danych pomiędzy stronami W tym rozdziale: * Dlaczego HTTP jest jak toczący się kamień? * Argumenty GET
** Inne użycie adresów URL w stylu GET
* Argumenty POST * Obsługa zmiennych GET/POST w PHP W tym rozdziale zajmiemy się przekazywaniem danych, na przykład zmiennych, pomiędzy stronami WWW. Niektóre z tych informacji nie należą jedynie do PHP, ale są konsekwencją interakcji PHP i HTML lub samego protokołu HTTP.
HTTP jest protokołem bezstanowym Ważne, abyś pamiętał, że sam protokół HTTP jest protokołem bezstanowym. Oznacza to, że każde wywołanie HTTP jest niezależne od innych, nie ma informacji na temat stanu klienta i nie jest zapamiętywane. Każde wywołanie powoduje utworzenie osobnego wątku, który ma za zadanie dostarczyć jeden plik, następnie jest niszczony (uściślając, wraca do puli dostępnych wątków). Nawet jeżeli projekt twojej witryny zakłada nawigację tylko w jedną stronę (ze strony 1. tylko do strony 2., a następnie do strony 3. itd.), protokół HTTP nigdy nie będzie wiedział,
czy użytkownik oglądający stronę 2. załadował wcześniej stronę 1. Nie możesz ustawić na stronie 1. zmiennej i oczekiwać, że zostanie ona zaimportowana do strony 2. tylko przez mechanizmy HTML. Możesz użyć HTML do wyświetlenia formularza, do którego można
wprowadzić informacje, ale jeżeli nie zrealizujesz mechanizmów przekazujących dane do innej strony lub programu, zmienne znikną w momencie przejścia na inną stronę.
226_________________________________________Część
l
»
Podstawy
PHP
Dla takich przypadków stworzone zostały technologie przetwarzania formularzy, np. PHP. PHP przechwytuje zmienne przenoszone z jednej strony do drugiej i pozwala na ich późniejsze wykorzystanie. Jest niezwykle użyteczny do funkcji przenoszenia danych i pozwala na ich łatwe zastosowanie w wielu przypadkach. Istnieją bardziej zaawansowane sposoby zapamiętania interakcji klienta z witryną, jak cookie oraz sesje. W tym rozdziale skupimy się tylko na podstawowych technikach przenoszenia danych pomiędzy stronami z zastosowaniem metod GET i POST z HTML. ^^^
^-A
Programiści ASP niezmiennie twierdzą, że PHP jest gorszy, ponieważ
uważają, że zmienne sesji są czymś niezwykłym. Nie daj się zakrzy-
czeć, Microsoft używa mechanizmu cookie do przechowywania zmiennych sesji, co może powodować wiele problemów. Możesz o tym
przeczytać w dodatku B.
Argumenty GET Metoda GET pozwala na przesyłanie argumentów pomiędzy stronami za pomocą fragmentu adresu URL. W przypadku użycia tej metody do obsługi formularzu, GET powoduje dodanie nazw zmiennych i ich wartości do adresu URL podanego jako atrybut ACTION. Poszczególne zmienne rozdzielone są znakiem zapytania. Kompletny adres URL przesyłany jest do przetworzenia (w tym przypadku przez PHP).
Poniżej przedstawiamy przykładowy formularz HTML używający metody GET. Przykład GET część 1
Gdy użytkownik wybierze jedną z wartości i kliknie przycisk, przeglądarka sklei bez dodatkowych odstępów następujące elementy:
•* adres URL podany w apostrofach po słowie ACTION (http://localhost/php/baseball.php); * znak zapytania (?);
Rozdział 12. » Przekazywanie danych pomiędzy stronami______________________227
* nazwę zmiennej, znak równości i jej wartość (Team=2); * znak & oraz kolejną parę NAME=VALUE (Submit=Submit). Ta część może być powtarzana tyle razy, na ile pozwala ograniczenie długości adresu przez serwer. Dla naszego przykładu utworzony zostanie następujący ciąg URL: http: //localhost/php/baseball .php?Team=Cubbies&Submit=Submit
Adres ten jest przesyłany przez przeglądarkę jako nowe żądanie. Skrypt PHP, do które-
go zostało przesłane powyższe żądanie, pobiera z adresu wartości GET i używa ich do stworzenia strony. W naszym przypadku wkleimy wybraną wartość do tekstu. Przykład GET część 2
Naprzód, !
Końcowy wynik przedstawiony jest na rysunku 12.1. Rysunek 12.1. Wynik działania formularza używającego
METHOD=GET
Obsługa formularzy za pomocą metody GET posiada jedną wielką zaletę w porównaniu z metodą POST. Tworzy ona różne adresy, które użytkownik może zapamiętać. Z wyniku działania formularza bazującego na metodzie POST nie da się zrobić zakładki. Sposób obsługi formularzy za pomocą metody GET posiada tyle wad, że standard HTML 4.0 odradza jego stosowanie. Wadami tymi są między innymi: * GET nie jest odpowiedni do logowania użytkownika, ponieważ nazwa użytkownika i hasło są widoczne na ekranie i mogą być zapisane w pamięci odwiedzonych stron w przeglądarce.
228_________________________________________Część l «
Podstawy PHP
* Wysłane przez formularz dane zapamiętywane są w logach serwera WWW. •* Ponieważ GET przypisuje dane do zmiennej środowiskowej serwera, jej długość jest ograniczona. Próba przesłania np. 300 słów w adresie URL nie jest
najlepszym pomysłem.
"<3
r3^^Ł |<>p-=Ęfr ••^
Oryginalna specyfikacja HTML określa maksymalną długość żądań na 244 znaki. Mimo że ograniczenie to zostało później zarzucone, używanie dłuższych ciągów nie jest dobrym pomysłem.
Ponieważ można zapamiętywać adresy utworzone przez metodę GET, pojawiło się wiele głosów za zachowaniem tej metody przez W3. Tak się stało i mimo że jest to metoda najczęściej używana do obsługi formularzy, jest zalecana tylko dla powtarzalnych zastosowań, czyli takich, które nie powoduj ą stałego efektu ubocznego. Najbardziej odpowiednim zastosowaniem GET jest okno przeszukiwania. Dla innych formularzy lepiej użyć metody POST.
Inne zastosowania adresów URL w stylu GET Mimo że w chwili obecnej obsługiwanie formularzy przez metodę GET nie jest zalecane, adresy URL w tym stylu są bardzo użyteczne do obsługi nawigacji po witrynie. Szczególnie użyteczne jest użycie ich w witrynach generowanych dynamicznie, które są często tworzone przy użyciu PHP, ponieważ adresy zawierające dołączone zmienne świetnie współpracują z systemem szablonów zależnych od kontekstu. Załóżmy, że jesteś właścicielem witryny traktującej o zwierzętach hodowanych dla wełny. Po długiej i ciężkiej pracy nad stroną informacyjną i graficzną masz następujące strony: alpaca.html guanaco.html llama.html vicuna.html
Lecz gdy witryna zacznie się rozrastać, płaska struktura plików może wymagać dużo pracy przy administracji, szczególnie gdy proste poprawki trzeba będzie wykonać na każdej stronie. Jeżeli struktura stron jest podobna, możesz zastanowić się nad zastosowaniem systemu szablonów razem z PHP. Można zastosować pojedynczy szablon oraz oddzielne pliki tekstowe dla każdego zwierzęcia (zawierające dane, fotografie itp.): fleecee.php alpaca.inc
guanaco.inc
llama.inc vicuna.inc
Rozdział 12. » Przekazywanie danych pomiędzy stronami______________________229
Można również użyć większej liczby wyspecjalizowanych szablonów: goat.php cashmere.inc insect.php silkworm.inc llamoid.php alpaca.inc rabbit.php angora.inc sheep.php merino.inc
W obu przypadkach plik szablonu będzie wyglądał podobnie (nie zamieściliśmy wszystkich niezbędnych plików, więc przykład ten nie będzie działał):
Łącza na panelu nawigacji są obsługiwane przez przeglądarkę tak samo jak wynik działania metody GET. Jednak nawet w przypadku takiego rozwiązania masz jeszcze wiele ręcznej pracy: należy się upewnić, że każdy włączany plik jest prawidłowo sformatowany, dodanie nowego pliku do witryny wymaga dodania nowego łącza i innych tego typu prac. Zgodnie
z zasadą oddzielania formy od treści możesz przejść na wyższy poziom abstrakcji przy
użyciu bazy danych. W tym przypadku adres typu: fleecee.php?animalID=2
powinien spowodować sięgnięcie przez szablon do bazy danych (użycie zmiennej numerycznej zamiast słowa przyspiesza interakcję z bazą danych). Taki system powinien automatycznie umieszczać na panelu na podstawie zawartości bazy danych. Dzięki temu możesz tworzyć kolejne strony WWW bez interwencji.
230_________________________________________Część l » Podstawy PHP
Argumenty POST POST jest zalecaną metodą obsługi formularzy, szczególnie dla niepowtarzalnych zastosowań (takich, które skutkują trwałymi efektami działania), takich jak dodawanie danych do bazy. Zbiór danych formularza jest zawarty w ciele formularza w czasie jego wysyłania do agenta przetwarzania (w tym przypadku PHP). Nie ma żadnych widocznych zmian w adresie URL w zależności od przesyłanych danych. Metoda POST posiada następujące zalety: *• Jest dużo bezpieczniejsza od GET, ponieważ wprowadzone przez użytkownika dane nie są widoczne w adresie URL, logach serwera oraz na ekranie (jeżeli są
prawidłowo obsłużone).
+ Maksymalny rozmiar przesyłanych danych jest dużo większy (kilka kilobajtów zamiast kilku setek znaków). Metoda ta posiada również wady: 4 Nie można utworzyć zakładki z wyniku działania. * Metoda ta może być niezgodna z niektórymi ustawieniami firewalla, jeżeli z powodów bezpieczeństwa usuwa on dane z formularza. W książce tej konsekwentnie używamy POST do obsługi formularzy umieszczających dane w systemie. GET używamy do nawigacji po witrynie oraz do obsługi przeszukiwania, czyli zastosowań wymagających odczytania danych i ich wyświetlenia. Wiele, jeżeli nie większość zastosowań POST powoduje zainicjowanie połączenia w usługowej warstwie systemu. Przykład pokazany na wydruku 12.1 jednak tego nie wykonuje (ponieważ skupiamy się na metodzie POST, usunęliśmy sprawdzanie poprawności danych, więc formularz ten wymaga jeszcze pracy). Wydruk 12.1. Arkusz oszczędności emerytalnych___________________________________ Przykład POST, część 1
/* To sprawdzenie pozwala na stwierdzenie, czy formularz
jest wyświetlony po raz pierwszy (w tym przypadku wyświetla tylko domyślny procent roczny), czy już zostały wysłane wprowadzone wartości */ if ( HsSet ($stage) )
Wypęłnij wszystkie pola (Poza "Koszyk") i sprawdź, ile pieniędzy zaoszczędzisz na emeryturę dla różnych przypadków! Możesz zmieniać wartości i ponownie przeliczać dane tak często,
jak chcesz. Musisz wypełnić dwa pola wieku. Pole "Procent roczny" posiada wartość domyślna, korygowaną o inflację (7% = wzrost 8% minus 1% inflacja),
którą możesz zmieniać w zależności od przypadku optymistycznego i
pesymistycznego.
Na rysunku 12.2 przedstawiony jest formularz z wydruku 12.1. Rysunek 12.2.
Formularz używający
metody POST
232_________________________________________Część
l
»
Podstawy
PHP
Zarządzanie zmiennymi w PHP PHP tak efektywnie przenosi dane, ponieważ projektanci podjęli bardzo wygodną, lecz (w teorii) ryzykowną decyzję. PHP automatycznie i niewidocznie dla użytkownika przypisuje zmienne na nowej stronie, gdy wyślesz je za pomocą GET lub POST. Większość z jego konkurentów wymaga jawnego wykonania tych przypisań na każdej stronie. Jeżeli o tym zapomnisz lub popełnisz błąd, dane nie będą dostępne dla agenta przetwarzania. PHP jest szybszy, prostszy i w większości przypadków odporny na pomyłki. Najprostszą metodą zilustrowania tej różnicy jest pokazanie różnych metod przetwarzania danych z tego samego formularza. Formularz ten wygląda następująco:
Formularz preferencji słodyczy
Skrypt PHP obshigujący formularz:
Odpowiedż na wybór preferencji
Hmmm
print("SCandy! "); if ($Candy -~ "orzeszki ziemne") print("Istniej e kiika świetnych rodzajów lodów zawierających małe lub połamane SCandy.");
else (
print("Myślę, że jeszcze nie istnieją lody zawierające $Candy, ");
print("ale bardzo potrzebne są lody zawierające SCandy.");
( ?>
Skrypt ASP realizujący te same funkcje (aby go użyć zmień argument ACTION formula-
rza na candy .asp):
Odpowiedź na wybór preferencji
Hmmm
<% Candy = Request.Form("Candy") %>
Rozdział 12. » Przekazywanie danych pomiędzy stronami______________________233 <%= Response.Write (Candy)%> <% If Candy = "orzeszki ziemne" Then %> Istnieje kilka świetnych rodzajów lodów zawierających małe lub połamane
<% Response.Write(Candy) %>. <% Else %>
Myślę, że jeszcze nie istnieją lody zawierające <% Response.Write(Candy) %>, <% End If %> <% If Candy = "snickers" Then %> ale czy próbowałeś loda <% Response.Write(Candy) %> '? <% Else If Candy = "krówki" Then %> ale bardzo potrzebne są lody zawierające <%
Response.Write(Candy) %>. <% End If %> <% End If %>
Wynik jest za każdym razem taki sam jak na rysunku 12.3. Rysunek 12.3.
Wynik użycia PHP lub ASP
Używanie GET i POST
Czy wiesz, że PHP może używać zarówno GET, jak i POST jednocześnie na jednej stronie? Możesz rzucić się w wir dynamicznego tworzenia formularzy! Szybko pojawia się pytanie: co się stanie, jeżeli (rozmyślnie lub nie) użyję tej samej nazwy zmiennej zarówno w tablicach GET, jak i POST. PHP przechowuje zmienne GET, POST oraz COOKIE w tablicach o nazwach $HTTP_GET_VARS, $HTTP_POST_VARS oraz $HTTP_COOKIE_VARS, jak również w tablicy $GLOBALS. Jeśli wystąpi konflikt, rozwiązywany jest przez nadpisywanie wartości zmiennych w kolejności ustalonej przez opcję gpc_order z pliku php.ini (należy ustawić również opcję track_vars). Późniejszy wygrywa nad wcześniejszym, więc jeżeli użyjesz ustawienia domyślnego GPC, cookie wygrają z POST, a te z GET. Możesz zarządzać kolejnością nadpisywania zmiennych, zmieniając kolejność tych trzech liter w odpowiednim wierszu pliku php.ini.
234_________________________________________Część
l
»
Podstawy
PHP
Ponieważ PHP posiada zdolność automatycznego przypisywania zmiennych, skrypt PHP pisze się szybciej. W skrypcie PHP po prostu używamy zmiennej bez konieczności pobierania jej wartości lub ponownej definicji. Przykład, jaki podaliśmy, jest trywialny, ponieważ przekazywana jest tylko jedna zmienna. Jednak przy bardziej złożonych formularzach z wieloma zmiennymi lub w przypadku serii formularzy współdzielących
wiele zmiennych PHP pozwala zaoszczędzić wiele czasu.
W skrypcie ASP należy odczytać każdą zmienną przysłaną za pomocą metody POST, w PHP nie jest to konieczne. W przypadku ASP należy użyć Request. Form w przypadku metody POST oraz Request .QueryString w przypadku metody GET. Jeżeli zmienisz metodę przesyłania danych, musisz wszędzie zmienić nazwę kolekcji, co mo-
że być źródłem błędów.
Automatyczne przypisywanie zmiennych w PHP również może być źródłem konfliktów nazw zmiennych. PHP po prostu zamieni starą wartość zmiennej na nową. Możesz sterować kolejnością zapisywania zmiennych za pomocą opcji GPC z pliku php.ini.
Najlepszą metodą jest jednak unikanie konfliktów i nadawanie dobrych, zróżnicowanych nazw zmiennych. Większość użytkowników PHP uważa, że użyteczność funkcji automatycznego przypisywania zmiennych przewyższa zagrożenie potencjalnymi konfliktami nazw zmiennych.
Podsumowanie Protokół HTTP jest protokołem bezstanowym. Oznacza to, że sam HTML nie potrafi
wymieniać danych pomiędzy stronami witryny WWW. Może zostać użyty do przekazywania wartości, ale zewnętrzny program obsługi formularza musi wysilić się, aby przekazać wartość. PHP jest prawdopodobnie najbardziej naturalnym programem obsługi formularza. Dane można przekazywać za pomocą trzech podstawowych metod: GET, POST oraz cookie (którymi zajmiemy się w rozdziale 26.). Metoda GET jest używana do tworzenia złożonych adresów URL, stosowanych wraz z szablonami w dynamicznych witrynach.
Nie jest to jednak metoda zalecana do obsługi formularzy, w przeciwieństwie do POST.
Rozdział 13.
Funkcje systemu operacyjnego i dostępu do plików W tym rozdziale: * Funkcje dostępu do plików * Funkcje operujące na katalogach * Funkcje sieciowe * Funkcje daty i czasu
* Funkcje konwersji kalendarza W rozdziale tym opiszemy wiele funkcji systemowych dostępnych w PHP. Wiele z nich pozwala na dostęp do funkcji systemowych protokołu HTTP. Najbardziej użyteczne są funkcje do odczytu i zapisu plików oraz funkcje zwracające datę i czas. Wykonanie wielu z funkcji pokazanych w tym rozdziale może mieć duży wpływ na bezpieczeństwo systemu. Używając ich, musisz pomyśleć o konsekwencjach. Nie chcemy cię przestraszyć. Po prostu nic, co pozwala zmienić system poprzez HTTP, nie powinno być lekceważone. Niektóre z tych funkcji działają w systemie Unix. Windows nie zawiera wielu narzędzi dostępnych w Uniksie. Jeżeli masz problem z uruchomieniem jakiejś funkcji na platformie Windows, upewnij się, że jest ona dostępna.
236_________________________________________Część l
» Podstawy PHP
Funkcje czytania i zapisywania plików Jest to bardzo użyteczny zestaw funkcji, a szczególnie w przypadku zbiorów danych, które są zbyt małe lub rozproszone, aby zapisywać je w bazie danych. Czytanie z pliku jest bezpieczne, jeżeli nie umożliwiasz odczytania hasła. Zapis do pliku może być nieco niebezpieczny.
Typowy przebieg operacji na pliku może przebiegać następująco: 1. Otwarcie pliku do czytania lub zapisu.
2. Odczyt pliku. 3. Zamknięcie pliku (może być wykonane później). 4. Przeprowadzenie operacji na pliku. 5. Zapis wyniku do pliku. Każdy z tych etapów jest realizowany przez osobną funkcję PHP.
Poniższy przykład ilustruje niektóre subtelności składni: $fd = fopen($filename, "r+") or die("Nie można otworzyć pliku $filename"); $fstring = fread(Sfd, filesize($filename)); Sfout = fwrite(Sfd, $fstring);
fclose(Sfd);
Wynikiem wykonania tego kodu jest zdublowanie zawartości pliku. Mówiąc inaczej, końcowym wynikiem działania będzie plik z zapisaną dwa razy oryginalną zawartością. Funkcja ta nie nadpisuje zawartości pliku.
Otwarcie pliku Wynik działania funkcji f open ( ) należy bezwzględnie przypisać do zmiennej (tradycyjnie $fd lub $fp, pochodzących od deskryptora lub wskaźnika pliku. Lepiej jednak
nadawać bardziej opisowe nazwy zmiennych). Jeżeli funkcja zadziała, PHP przypisze do zmiennej wartość całkowitą, która jest potrzebna do dalszych operacji na tym pliku, takich jak f read lub fwrite. Jeżeli funkcja się nie powiedzie, zwracana jest wartość FALSE. System udostępnia tylko określoną liczbę deskryptorów pliku, co powoduje, że pliki należy zamykać tak szybko, jak tylko możliwe. Jeżeli spodziewasz się dużego zapotrzebowania i masz dostęp do ustawień systemowych, możesz powiększyć liczbę dostępnych plików.
Pliki można otwierać w sześciu trybach (podobnie do poziomów dostępu). Jeżeli spróbujesz wykonać operację niedozwoloną w danym trybie, nie zostanie ona wykonana:
Rozdział 13. » Funkcje systemu operacyjnego i dostępu do plików________________237
* Tylko odczyt (r). * Odczyt i zapis do istniejącego pliku (r+): zapis będzie realizowany na początku pliku. * Tylko zapis (w): jeżeli plik nie istnieje, jest tworzony, zawartość istniejącego
pliku jest usuwana.
* Zapis i odczyt, nawet gdy plik nie istnieje (w+): jeżeli plik nie istnieje, jest tworzony, zawartość istniejącego pliku jest usuwana. * Tylko zapis na koniec istniejącego lub nieistniejącego pliku (a). + Odczyt i zapis na końcu pliku istniejącego lub nieistniejącego pliku (a+). Przed użyciem trybów w lub w+ należy się upewnić, że poprzednia zawartość pliku została zapisana. W przypadku użycia innych trybów możliwość utraty danych jest dużo mniejsza.
Niektórzy użytkownicy mieli problemy z użyciem trybów +. Wiele z tych problemów wynikało z niezrozumienia różnic pomiędzy trybami. Jeżeli nie jesteś czegoś pewien, spróbuj otworzyć plik osobno w trybie odczytu i zapisu. Przeczytaj również fragment o zapisie plików.
Odmiany otwierania plików Istnieją cztery podstawowe typy połączeń, za pomocą których można otwierać pliki: HTTP, FTP, IO oraz system plików. HTTP fopen
Funkcja fopen próbuje otworzyć połączenie HTTP 1.0 do pliku, który może zostać przesłany przez serwer WWW (pliki typu HTML, PHP, ASP itd.). PHP „oszukuje" serwer WWW tak, aby wydawało mu się, że żądanie dostępu do pliku zostało przesłane przez przeglądarkę, a nie przez funkcję otwarcia pliku. Powinieneś używać znaków ukośnika zarówno w systemach Unix, jak i Windows: $fd = fopen("http://www.somedomain.org/openfile.html/", "r");
Musisz pamiętać o końcowym ukośniku, ponieważ funkcja ta nie obsługuje przekierowań. Pamiętaj jednak, że nie musisz koniecznie używać HTTP do dostępu do plików HTML. Możesz po prostu otworzyć go z systemu plików, traktując jak zwykły plik tekstowy. Pokazana powyżej metoda jest szczególnie przydatna do zdalnych serwerów WWW. Efekt działania jest podobny do obejrzenia strony HTML i zapisania jej źródła. FTP fopen
Ten rodzaj funkcji fopen próbuje zestawić połączenie FTP do zdalnego serwera, udając klienta FTP. Jest to najbardziej sprytna z podanych czterech wersji, ponieważ musisz podać nazwę użytkownika i hasło oprócz nazwy komputera i ścieżki do pliku.
238_________________________________________Część l »
Aby metoda ta prawidłowo działała, serwer FTP musi obsługiwać tryb pasywny. Dzięki FTP pliki mogą być otwierane w trybach tylko do odczytu lub tylko do zapisu. Fopen dla standardowego wejścia lub wyjścia
Operacje na standardowym wejściu lub wyjściu są określane poprzez php://stdin, php: / / s t d o u t lub php: / / s t d e r r (w zależności od strumienia). Takiej operacji używa się tylko, gdy PHP jest używany w wierszu komend jako systemowy język skryptowy w rodzaju języka Perl, ponieważ standardowe wejście lub wyjście jest powiązane z oknem terminala. Zastosowanie jest na tyle rzadkie, że nie znaleźliśmy ani jednego przykładu zastosowania. Fopen dla systemu plików
Zwykłym sposobem użycia f open jest użycie systemu plików. Jeżeli nie wskazałeś inaczej, PHP próbuje otworzyć plik korzystając z systemu plików. W systemie Windows możesz używać formatu ścieżki, ale musisz pamiętać o stosowaniu podwójnych znaków \: $fp = fopen("c:\\php\\phpdocs\\navbar.inc", "r");
Pamiętaj, że pliki i katalogi muszą być dostępne do odczytu lub zapisu dla użytkownika zalogowanego do procesu PHP, a nie tylko dla użytkownika systemowego. Jeżeli udostępniasz serwer, musisz pamiętać, aby inni użytkownicy PHP mogli czytać lub zapisywać twoje pliki. Wiemy jednak, że nie jest to całkowicie bezpieczne.
Czytanie pliku Funkcja f read ( ) wymaga wskaźnika pliku oraz wielkości pliku jako argumentów. Jeżeli rozmiar pliku nie jest wystarczający do odczytania całego pliku, mogą wystąpić problemy (chyba że podajesz mniejszą wartość, aby odczytywać plik we fragmentach). PHP może samodzielne obliczyć wielkość pliku, używając funkcji f ilesize () z nazwą pliku (lub zmienną) jako argumentem. Sfstring = fread($fd, filesize($filename));
Częstym błędem jest wpisywanie f i l e s i z e ( $ f d ) zamiast filesize ( $ f i l e n a m e ) . Jest to bardzo użyteczna funkcja, ponieważ pozwala zamienić plik na ciąg, nad którym można pracować za pomocą wielu funkcji działających na ciągach. Każdy ciąg można zamienić na tablicę, używając funkcji f i l e () lub explode (), co daje nam dostęp do wielkiego arsenału funkcji manipulujących tablicami. PHP zawiera więcej funkcji tnących i szatkujących niż cały zestaw narzędzi chirurgicznych. Jeżeli chcesz wyświetlić plik na standardowe wyjście (dla większości instalacji PHP jest to przeglądarka), możesz użyć funkcji readf ile ( ) . Funkcja ta ma wbudowane otwarcie
Rozdział 13. » Funkcje systemu operacyjnego i dostępu do plików_______________239
pliku, więc nie musisz używać do tego osobnej funkcji. Jeżeli chcesz czytać i wykonywać operacje na kolejnych wierszach pliku, możesz używać f gets ( ) zamiast f read ( ) . $fd = fopen{"plikprzykladowy.inc", "r");
while (Ifeof(Sfd)) {
Ślinę = fgets($fd, 4096);
if (strcmp(Sline, $targetline) — 0) echo "Ciąg został znaleziony!";
} fclose ($fd);
Jeżeli chcesz odczytać plik jako tablicę, możesz użyć funkcji file (}. Tworzy ona tablicę, w której każdy element jest wierszem oryginalnego pliku, wraz ze znakiem kończącym wiersz. Funkcja f i l e d nie wymaga osobnego otwarcia i zamknięcia pliku. Poniższa linia używająca f i l e (}: $line_array = file("plik.inc");
Jeżeli zamierzasz odczytać plik znak po znaku, możesz użyć funkcji fgetc ( ) . Zwraca znak ze wskaźnika pliku aż do końca pliku.
Zapis do pliku Jeżeli prawidłowo otwarłeś plik w odpowiednim trybie, zapis danych do pliku jest już bardzo prosty. Funkcja f write ( ) pobiera wskaźnik do pliku jako argument, zapisywany ciąg znaków oraz opcjonalnie długość w bajtach. Parametr ten nie powinien być używany oprócz niektórych specyficznych sytuacji. Funkcja zwraca liczbę zapisanych
znaków.
$fout = fwrite(Sfp, Sstring); echo "Zapisałem do pliku Sfout znaków";
Funkcja f put s ( ) jest identyczna z fwrite ( ) . Jedynie nazwa fputs ( ) jest w stylu języka C. Należy zapamiętać, że zapis do pliku w trybach w lub w+ powoduje całkowite i nieodwracalne usunięcie całej dotychczasowej zawartości pliku. Tryby te są przeznaczone jedynie do całkowitego nadpisywania zawartości. Jeżeli chcesz dopisać dane na początku lub końcu istniejącego pliku, użyj trybów r+ lub a+.
Najczęściej spotykanym błędem użycia trybów zapisu w PHP jest sposób realizowania edytowania pliku tekstowego w przeglądarce (przy użyciu formularza HTML). Jeżeli chcesz otworzyć plik, odczytać jego zawartość, następnie zapisać zmienioną wersję tego pliku, nie możesz korzystać z trybów "w+". Tryby w usuwają zawartość pliku natychmiast po jego otwarciu; możesz czytać z pliku otwartego w trybie w+ jedynie te dane, które zostały do niego zapisane po otwarciu. Aby obejść to ograniczenie, należy raz otworzyć plik do odczytu i raz do zapisu tak, jak zostało to pokazane w przykładzie ($f ilename zawiera nazwę pliku tekstowego).
240_________________________________________Część l » Podstawy PHP
if (IsSet($submited)) ( $fd = fopen($filename, "w+") or die ("Nie można otworzyć pliku Sfilename"); Sfout = fwrite($fd, $newstring); fclose ($fd); } Sfd = fopen (Sfilename, "r"} or die ("Nie można otworzyć pliku Sfilename"); Sinitstring = freadISfd, filesize(Sfilename)); fclose(Sfd); echo echo echo echo
""; "";
echo ""; ?>
Powtórzmy jeszcze raz, że zapisywanie plików nie jest dobrym pomysłem, chyba że możesz bardzo dokładnie konfigurować środowisko pracy programu! Dobrze zabezpieczony serwer Intranetu może być odpowiedni dla takich działań, ale zapisywanie na
produkcyjnej witrynie niesie ze sobą spore niebezpieczeństwo. Więcej na ten temat znajduje się w rozdziale 31. „Bezpieczeństwo i kryptografia".
Jeżeli samodzielnie kompilowałeś PHP i znasz C, możesz zablokować możliwość zapisu do pliku (a właściwie zablokować możliwość otwarcia pliku w trybie zapisu — efekt jest identyczny). Jest to dobry pomysł w przypadku, gdy twoja witryna korzysta z bazy danych. Aby zablokować zapis do plików, należy odszukać w głównym katalogu PHP plik o nazwie fopen-wrappers.c. Po otwarciu tego pliku w edytorze odszukaj definicję funkcji php__f open_with_path ( ) . Należy dodać w odpowiednim miejscu (na przykład 10 linii od początku funkcji) następujące linie: // dopuszczam tylko tryb "r"
if (!strcmp(mode, "r")) return NULL;
Można również zablokować jeszcze kilka opcji, ale pozostawimy w twojej gestii. Jeżeli zablokujesz możliwość zapisu do pliku, a skrypt spróbuje to zrobić, otrzymasz błąd analizatora składni „variable passed to file is not an array or object".
Zamknięcie pliku Operacja zamknięcia pliku jest bardzo prosta: fclose($ d)
W przeciwieństwie do fopen ( ) , wynik funkcji fclose ( ) nie musi być przypisywany do zmiennej. Zamykanie pliku wydaje się być stratą czasu, ale twój system posiada
Rozdział 13. « Funkcje systemu operacyjnego i dostępu do plików_______________241
określoną liczbę dostępnych uchwytów plików. Może więc ich zabraknąć, jeżeli nie będziesz zamykał plików.
Funkcje systemu plików i katalogów Większość z tych funkcji będzie znana użytkownikom Uniksa, ponieważ dokładnie powielają one polecenia systemowe. Większość z funkcji opisanych poniżej niesie pewne ryzyko, ponieważ powiela funkcje, które są i powinny być wykonywane przez lokalny komputer. Niektóre z tych funkcji działają jedynie, gdy proces PHP jest uruchamiany z prawami administratora. Ponieważ nie jest to domyślne ustawienie, więc tylko administratorzy,
którzy z rozmysłem ustawiaj ą taką konfigurację, strzelaj ą sobie samobójczą bramkę.
Najpierw wymienimy najczęściej wykorzystywane i bezpieczne funkcje; te rzadziej wykorzystywane i mniej bezpieczne znajdują się w tabeli 13.1.
feof Funkcja feof ( ) pobiera nazwę pliku jako argument i sprawdza, czy wskaźnik pliku znajduje się na jego końcu.
file_exists Funkcja f ile_exists () jest prostą funkcją, której będziesz często używał korzystając z innych funkcji systemu plików. Sprawdza ona, czy plik o podanej nazwie istnieje
w systemie.
if {!file_exists("test.php")) <
$fd = fopen("test.php", "w+");
)
Funkcja zwraca wartość TRUE, jeżeli plik istnieje, lub FALSE, jeżeli nie został odnaleziony. Wynik testu jest zapisywany w pamięci podręcznej, którą można wyczyścić za pomocą funkcji clearstatcache ( ) .
filesize Kolejną prostą lecz użyteczną funkcją jest filesize ( ) , która zwraca i zachowuje w pamięci podręcznej rozmiar pliku w bajtach. Użyliśmy jej w przykładach korzystających z funkcji f read ( ) . Nigdy nie przekazuj wielkości pliku za pomocą liczby, jeżeli
możesz zrobić to za pomocą funkcji f i l e s i z e f ) .
242_________________________________________Część
l
»
Podstawy
PHP
Tabela 13.1.
Funkcje systemu plików
Funkcja
Opis
basename (ścieżka)
Zwraca nazwę pliku z pełnej ścieżki do pliku
chgrpiplik, grupa)
Zmienia grupę pliku w jedną z grup, do których należy proces PHP. Nie działa w Windows
chmod(plik, tryb)
Zmienia tryb dostępu na podany w systemie ósemkowym. Nie działa w Windows
chown (plik, użytkownik)
Jeżeli funkcja jest wykonywana przez administratora, zmienia właściciela pliku na podanego użytkownika. Nie działa w Windows
clearstatcache ( )
Czyści pamięć podręczną danych o plikach
copytpJiAr,
Kopiuje plik w podane miejsce
cel)
delete (plik)
Patrz unlink
dirname (ścieżka)
Zwraca katalog z podanej pełnej ścieżki do pliku
diskf reespace ( "/katalog")
Zwraca ilość dostępnego miejsca w podanym katalogu
f g e t c s v f f p , długość, ogranicznik)
Czyta i przetwarza linię z pliku w formacie CSV
f g e t s s ( f p , długość [, dostępne znaczniki})
Czyta z pliku wiersz (zakończony znakiem nowego wiersza) i usuwa znaczniki HTML i PHP oprócz tych, które zostały dopuszczone w wywołaniu funkcji
f i l e a t i m e (plik)
Zwraca (i zapamiętuje w pamięci podręcznej) datę i czas ostatniego dostępu do pliku
f i l e c t i m e (plik)
Zwraca (i zapamiętuje w pamięci podręcznej) datę i czas ostatniej zmiany i-node
f ilegroup (plik)
Zwraca (i zachowuje w pamięci podręcznej) identyfikator grupy pliku. Nazwa grupy może być odczytana za pomocaposix getgrid ( )
f ileinode (plik)
Zwraca (i zachowuje w pamięci podręcznej) i-node pliku
f ilemtime (plik)
Zwraca (i zachowuje w pamięci podręcznej) datę i czas ostatniej
modyfikacji pliku
fileowner (plik)
Zwraca (i zachowuje w pamięci podręcznej) identyfikator właściciela pliku. Nazwa właściciela może zostać odczytana za pomocą posix g e t p w u i d l )
f ileperms (plik)
Zwraca (i zachowuje w pamięci podręcznej) poziom dostępu do pliku
f iletype (plik)
Zwraca (i zachowuje w pamięci podręcznej) jeden z typów pliku: fifo, char, dir, block, link, file, unknown
f lock (plik, operacja)
Funkcja blokowania pliku. Wartość parametru musi wynosić: 1 (współdzielony), 2 (na wyłączność), 3 (zwolnienie blokady) lub +4 (bez blokady w czasie blokowania)
fpassthru ( f p)
Przesyła na standardowe wyjście wszystkie dane z pliku określonego przez deskryptor fp
Rozdział 13. » Funkcje systemu operacyjnego i dostępu do plików________________243
Tabela 13.1.
Funkcje systemu plików (ciąg dalszy)
Opis
Funkcja fseekffp, skąd)
przesuniecie,
Przesuwa wskaźnik pliku o liczbę bajtów równą przesunięciu, rozpoczynając od pozycji określonej przez parametr „skąd"
f t e l l (fp)
Zwraca pozycję wskaźnika pliku
set file b u f f e r ( f p [, rozmiar bufora]
Ustawia wielkość bufora zapisu do pliku. Domyślna wartość to 8 KB
is dir (katalog)
Zwraca (i zachowuje w pamięci podręcznej) wartość TRUE, jeżeli istnieje podany katalog
is executable (plik)
Zwraca (i zachowuje w pamięci podręcznej) wartość TRUE, jeżeli plik jest plikiem wykonywalnym
is_file (plik)
Zwraca (i zachowuje w pamięci podręcznej) wartość TRUE, jeżeli plik jest zwykłym plikiem
is l i n k t p l i t )
Zwraca (i zachowuje w pamięci podręcznej) wartość TRUE, jeżeli plik jest dowiązaniem
is readable (plik)
Zwraca (i zachowuje w pamięci podręcznej) wartość TRUE, jeżeli plik może być odczytany przez PHP
is
Zwraca (i zachowuje w pamięci podręcznej) wartość TRUE, jeżeli PHP może zapisywać do podanego pliku lub katalogu
w r i t a b l e (plik/katalog)
l i n k (cel, plik)
Tworzy dowiązanie. Nie działa w Windows
linkinfo (ścieżka)
Potwierdza istnienie dowiązania. Nie działa w Windows
mkdir (ścieżka, tryb]
Tworzy podkatalog w katalogu określonym przez ścieżkę Prawa dostępu są określone przez parametr „tryb" w systemie ósemkowym
pclose (fp)
Zamyka deskryptor pliku procesu otwarty przez popen ( )
popen ( komenda , tryb)
Otwiera plik procesu
readlink ( d o w i ą z a n i e )
Zwraca obiekt zwracany przez dowiązanie. Nie działa w Windows
rename( stara nazwa, nowa nazwa)
Zmienia nazwę pliku
rewind (fp)
Przesuwa wskaźnik pliku na początek pliku
rmdir (katalog)
Usuwa pusty katalog
stat (plik)
Zwraca wybrane informacje o pliku
Istat (plik)
Zwraca wybrane informacje o pliku lub dowiązaniu
s y m l i n k ( c e J , łącze)
Tworzy łącze symboliczne pomiędzy obiektem docelowym a łączem. Nie działa w Windows
touch (plik [ , c z a s ] )
Ustawia datę modyfikacji pliku
umask (maska)
Zwraca wartość umask i ustawia go na & 0777. Wywołany bez argumentów zwraca tylko wartość umask
Funkcje sieciowe Funkcje sieciowe to zbiór stosunkowo rzadko używanych funkcji umożliwiających tworzenie połączeń sieciowych oraz zwracających informacje. Uruchamia się je z wiersza
poleceń, chyba że tworzysz narzędzia monitorujące pracę urządzeń sieciowych.
Funkcje logu systemowego Funkcje logu systemowego pozwalają na otwarcie go dla potrzeb programu, wygenerowanie komunikatu oraz zamknięcie: * o p e n l o g f [ i d e n t ] , opcja, facil ty) jest opcjonalna, jeśli używa się jej wraz z funkcją syslog ( ) . Wartość ident jest generowana automatycznie; ^ s y s l o g ( priorytet, komunikat);
•* closelog ( ) jest opcjonalna, jeżeli używa się jej wraz z funkcją syslog ( } .
Funkcje DNS PHP oferuje kilka funkcji odpytujących DNS; zebraliśmy je w tabeli 13.2. Tabela 13.2.
Funkcje DNS Funkcja
Opis
checkdnsrr ($/iost, [Styp] )
Sprawdza, czy istnieje zapis w DNS. Domyślnym typem jest MX,
inne typy to: A, ANY, CNAME, NS, SOA gethostbyaddr ($adresip)
gethostbyname ( $ n a z w a _ h o s t a )
Pobiera nazwę komputera o podanym adresie
Pobiera adres komputera o podanej nazwie
get host byname l ($nazwa_hosta) Pobiera listę adresów odpowiadających podanej nazwie komputera
getmxrr ($nazwa_hosta,
[tablica hosty_mx] , [ w a g a ] )
Sprawdza, czy istnieją wpisy MX dla podanego komputera. Wynik zostaje umieszczony w tablicy hosty mx, wypełnia również
informacje o wadze
Funkcje gniazd Gniazdo jest rodzajem dedykowanego połączenia, umożliwiającego komunikację różnych programów (mogą być uruchomione w różnych komputerach) poprzez przesyłanie tekstu. Funkcje PHP operujące na gniazdach pozwalają na tworzenie przez skrypt połączenia do serwera, który komunikuje się dzięki gniazdom. Po połączeniu dalsza komunikacja odbywa się przy wykorzystaniu zwykłych funkcji zapisujących i odczytujących pliki (fputs (), f gets () itd.).
Rozdział 13. » Funkcje systemu operacyjnego i dostępu do plików_______________245
Standardową funkcją otwierającą gniazdo jest f sockopen ( ) . Funkcja p f sockopen ( ) również otwiera gniazdo, ale połączenie nie jest zrywane po zakończeniu skryptu. Blokowa-
nie połączenia przez gniazdo może być włączane za pomocą funkcji set_socket_blocking ( ) . Po uaktywnieniu blokowania funkcje odczytujące z gniazda zatrzymują się do czasu odczytania danych z gniazda. Wyłączenie blokowania powoduje, że funkcje czytające są natychmiast kończone, jeżeli nie ma danych do odczytania. Funkcje te są zebrane w tabeli 13.3. Tabela 13.3.
Otwiera połączenie poprzez gniazdo z podanym portem komputera i zwraca wskaźnik pliku, który może być używane w funkcjach typu fgets() Zwraca numer portu używany przez podaną usługę
getservbyport ($port, $protokól)
Zwraca usługę używającą podanego portu
pf sockopen ($host, $port, [numer^błędu],
Otwiera trwałe połączenie z gniazdem
[ciąg_błędu] , [czas o c z e k i w a n i a ] )
set_socket_blocking gniazda, Stryb)
($desJcryptor_
Ustawia tryb blokowania: TRUE zblokowaniem, FALSE bez blokowania. Domyślnie — tryb bez
blokowania
Funkcje daty i czasu Funkcje te stanowią podstawowe narzędzia do budowy własnych funkcji. Możesz użyć ich do prostego wyświetlenia daty i czasu, do mierzenia czasu wykonania skryptu PHP
lub do uruchamiania funkcji w określonym czasie (na przykład funkcji wyświetlającej napis „Wesołych Świąt"). Działanie tych funkcji łatwo zrozumieć, jeżeli wiesz, co to jest znacznik czasu z systemu Unix. Funkcje te można podzielić na trzy rodzaje: zwracające datę lub czas, formatujące datę lub czas oraz sprawdzające poprawność daty. Znacznik czasu Uniksa to liczba sekund od początki epoki Uniksa (północ l stycznia 1970 roku według czasu Greenwich). Funkcje te działają również w Windows.
Jeżeli nie znasz daty ani czasu Najszybszą metodą odczytania czasu jest użycie funkcji time ( ) . Zwraca ona znacznik
czasu Uniksa dla twojej strefy czasowej w postaci np.: „961906652". Jest to najlepszy
246_________________________________________Część l » Podstawy PHP
format, jeżeli chcesz przekazać ten znacznik do innej funkcji lub programu. Przy użyciu funkcji opisanych w dalszej części rozdziału można przetworzyć tę wartość do postaci
czytelnej dla człowieka.
Aby uzyskać mikrosekundy i sekundy upływające od początku epoki Uniksa, należy użyć funkcji microtime ( ) . Jest ona bardzo przydatna dla narzędzi mierzących wydajność. Zwracany wynik ma postać „0.74321900 961906846", w którym pierwsza część to mikrosekundy, a druga to znacznik czasu Uniksa. Jeżeli chcesz (na przykład) mierzyć
wydajność różnych fragmentów strony WWW, musisz użyć mikrosekund, które mogą być wycięte w następujący sposób:
$chunks = explode{ " ", $stamp ); $microseconds = chunks[O]; echo Smicroseconds; ?>
^
Podstawową funkcją zwracającą datę jest getdate ($timestamp). Zwraca tablicę
asocjacyjną z następującymi elementami: sekundy minuty godziny Mday: dzień miesiąca 1-31
Wday: dzień tygodnia 1-7 Mon: miesiąc 1-12
Rok Yday: dzień roku l - 356 Weekday: dzień tygodnia Sunday-Saturday
Month: January-December Najczęściej używaną konstrukcją jest getdate (time ( ) ) , lecz można użyć getdate ( ) z dowolną wartością $timestamp.
Jeżeli chcesz za jednym razem pobrać czas i sformatować go, należy użyć funkcji datę ( ) zamiast getdate ( ) . Jeżeli nie zostanie podany znacznik czasu, datę ( ) automatycznie użyje bieżącej daty i czasu. Funkcja ta lepiej formatuje wynik (patrz dalsza część rozdziału). Funkcja strftime ( ) także formatuje bieżący znacznik czasu (również ją opiszemy później), jeżeli nie podamy innego.
Jeżeli już odczytałeś datę i czas Funkcje opisane w tej części służą do precyzyjnego formatowania daty i czasu. Chcesz np. wyświetlać daty w formacie europejskim (2000.04.20) zamiast amerykańskim (4/20/2000).
Rozdział 13. » Funkcje systemu operacyjnego i dostępu do plików________________247
Podstawową metodą formatowania znacznika czasu jest użycie datę ( $ format . . . Sformatn [, $ times tamp] ). Przekazujesz do funkcji serię kodów określających
twoje wymagania co do formatowania oraz opcjonalnie znacznik czasu. Możesz wybrać
datę z dwucyfrowym zapisem dni, format 12- lub 24-godzinny czasu oraz skróty nazw miesięcy (wszystkie opcje znajdują się w podręczniku PHP). Analogiczną funkcją jest gmdate ($format . . . $formatn [ , Stimestamp] ) , która zwraca datę według
czasu Greenwich.
Funkcja strftime ($format .. . Sformatn [Stimestamp]) ma podobne działanie, lecz przeznaczona jest do formatowania czasu, nie daty. Funkcja gmstrftime ($ format ... Sformatn [, $ times tamp] ) zwraca sformatowany czas Greenwich.
Funkcja m k t i m e ( ) konwertuje dowolną datę na znacznik Uniksa. Różni się nieco kolejnością parametrów od komendy Uniksa o tej samej nazwie. Funkcja g m m k t i m e O
robi to samo dla czasu Greenwich.
Na koniec przedstawimy funkcję checkdate (Smiesiąc, Odzień, $rok), która sprawdza poprawność podanej daty. Za jej pomocą można szybko sprawdzić, czy rok jest przestępny.
Funkcje konwersji kalendarza Funkcje konwersji kalendarza są dostępne dla tych, którzy mogą skompilować PHP
z dynamiczną biblioteką obsługi kalendarzy.
Wielu początkujących użytkowników PHP myli się uważając „funkcje kalendarza" za funkcje daty. Funkcje te po prostu konwertują daty pomiędzy różnymi (i w większości historycznymi) kalendarzami. Jeżeli uważasz, że trafiłeś tu omyłkowo, przejdź do części „Funkcje daty i czasu" we wcześniejszej części tego rozdziału.
Jeżeli zajmujesz się historią Pranej i, będziesz zadowolony, że za pomocą kilku wierszy
kodu możesz konwertować daty z kalendarza rewolucji francuskiej na kalendarz gregoriański. Można powiedzieć: Bon Thermidor, Citoyens et Citoyennes! Funkcje te naprawdę maj ą użytkowników — szczególnie w Internecie.
Aby użyć funkcji kalendarza, należy samemu skompilować PHP. Funkcje te znajdują się w jeszcze niestabilnej bibliotece dynamicznej opisanej w pliku dl/README. W czasie pisania tej książki funkcje kalendarza nie były dostępne w binarnej wersji dla Windows. Konwersja pomiędzy kalendarzami jest możliwa, ponieważ wszystkie funkcje kalenda-
rza współdzielą uniwersalne odwołanie, tzw. „numer dnia juliańskiego" Jest to liczba będąca liczbą dni od południa pierwszego stycznia 4713 roku p.n.e. według kalendarza juliańskiego. To 14 stycznia w kalendarzu gregoriańskim. Tak zwana „data juliańska"
248_________________________________________Część
l
»
Podstawy
PHP
jest liczbą double, reprezentującą liczbę dni i godzin od zerowego dnia juliańskiego. PHP nie pozwala na taki poziom dokładności. Wspomnieliśmy o tym na wypadek, gdy-
by ktoś szukał tej informacji.
Pamiętaj, że dzień juliański zmieniał się w południe, a nie o północy.
Funkcje konwersji kalendarza zamieniają datę w kalendarzu na numer dnia juliańskiego, i na odwrót. Aby skonwertować datę pomiędzy kalendarzami, należy użyć dwóch funkcji: zamieniającej datę na numer dnia juliańskiego oraz zmieniającej NDJ na datę
w innym kalendarzu. W naszym przykładzie zamieniamy datę kalendarza gregoriańskiego na datę kalendarza żydowskiego. $jd_no = gregoriantojd(8, 11, 1945); Shebrew = jdtojewish($jd_no);
echo Shebrew;
Wykonanie tego fragmentu zwróci datę 2, 6 [ E l u l ] , 5705. W chwili obecnej dostępne są kalendarze: «• Republiki Francuskiej;
** gregoriański; * żydowski; * juliański;
* Uniksa. Każdy z tych kalendarzy posiada parę funkcji j dtoX oraz xto j d. Istnieją jeszcze dwie inne pary funkcji kalendarza. JDMonthName ( ) i JDDayofWeek ( ) . Zwracaj ą miesiąc i dzień tygodnia dla dowolnego numeru dnia juliańskiego we wszystkich obsługiwanych kalendarzach. Funkcje easter_date ( ) i easter_days ( ) obliczają, kiedy przypada Wielkanoc (katolicka) w dowolnym roku. Easter_date ( ) jest
prostsza, ale może być używana tylko w obrębie dat systemu Unix (1970-2037). Zwraca ona znacznik czasu północy w Wielkanoc w podanym roku.
Podsumowanie PHP posiada wiele wbudowanych funkcji, operujących na systemie plików oraz systemowych, które mogą być użyteczne, ale niosą pewne ryzyko. Dla przykładu, istnieje wiele funkcji powielających narzędzia systemowe Uniksa, takie jak chmod ( ) czy copy ( ) . PHP posiada również bardziej zaawansowane funkcje, na przykład odpytujące DNS. Mimo że lepiej wyłączyć niektóre z nich, mogą być bardzo przydatne, w odpowiednio zaprojektowanym środowisku. Funkcje PHP pozwalające na otwarcie, odczyt i zapis plików są bardzo silnym narzędziem. Większość problemów związanych z tymi
Rozdział 13. » Funkcje systemu operacyjnego i dostępu do plików_______________249
funkcjami wynika z nieprawidłowego zrozumienia trybów otwarcia plików. PHP pozwala również na otwarcie pliku poprzez HTTP, ftp i standardowe wejście i wyjście. PHP posiada również wiele funkcji określających datę i czas, więc zawsze będziesz wiedział, która jest godzina.
250
______________________________________Część l
«
Podstawy PHP
Rozdział 14.
Styl PHP W tym rozdziale:
* Jak dostać punkty za styl
* Komentowanie kodu * Pisanie kodu łatwego do konserwacji
+ Łączenie PHP i HTML + Oddzielenie funkcji od układu strony W tym rozdziale opiszemy główne punkty stylu PHP oraz sposoby polepszenia funkcjonalności, łatwości utrzymania i atrakcyjności kodu. Zawartość tego rozdziału ma pomóc początkującym programistom PHP wybrać styl, w jakim będą pisali programy. Większość z tych porad ma zastosowanie we wszystkich językach programowania. Mamy nadzieję pomóc nowym programistom PHP rozszyfrować kod pisany przez innych. Czytanie trzech różnych podręczników, które sanie ze sobą zgodne i brak w nich wyjaśnienia przyczyn tej niezgodności, może być dla uczącego się pisać skrypty bardzo denerwujące. Informacje zawarte w tym rozdziale powinny pomóc zidentyfikować istotne fragmenty kodu, ukryte w stylistycznych udziwnieniach, i lepiej objaśnić analizowany kod.
Zalety prawidłowego stylu Najważniejszym celem pisania kodu jest oczywiście realizowanie założonych funkcji. Jeżeli skrypt PHP działa, kto ma czas i ochotę patrzeć, jak on wygląda? Istnieje jednak olbrzymia różnica pomiędzy skleceniem programu, byle działał, a pisaniem poprawnie skonstruowanego kodu, który jest zrozumiały dla innych. Programiści PHP stykają się z takimi samymi zagadnieniami jak inni:
252_________________________________________Część l
»
Podstawy PHP
4 Czytelność: na pewno rozumiesz to, co właśnie napisałeś, ale czy zrozumie to następna osoba? A jeżeli tą następną osobą będziesz ty? * Łatwość w utrzymaniu: co się stanie, jeżeli witryna porad medycznych w końcu zmieni podawanie temperatury ze stopni Fahrenheita na Celsjusza? Nieprawidłowa odpowiedź to: zmiana 790 wystąpień ciągu 98,6 w kodzie. * Solidność: witryna działa świetnie, jeżeli otrzymujesz dane wejściowe, których się spodziewasz. A jak działa dla nieprawidłowych danych? * Zwięzłość i efektywność: szybki kod jest lepszy niż powolny; mniejszy kod jest lepszy niż obszerny. W tym rozdziale przeprowadzimy krótki przegląd niektórych strategii osiągania tych celów w PHP. Następnie zajmiemy się unikalnymi sposobami organizacji kodu.
Czytelność Podstawowa cecha skryptu to czytelność. Oko ludzkie lubi wyraźne wzory, logiczną organizację oraz znaczące powtórzenia. Czytelności sprzyja również umieszczanie najważniejszego słowa na początku wiersza, a nie ukrywanie go w środku. Jeżeli projektujesz stronę HTML przy użyciu narzędzia wizualnego, noty za czytelność nie będą zbyt wysokie. Programy te notorycznie generują źle sformatowany i zorientowany na grafikę kod HTML, wypełniony niewidocznymi rysunkami GIF, absolutnym skalowaniem i innymi tego typu niedociągnięciami. Wszystkie te błędy znajdują się w poniższym przykładzie, który został wygenerowany przez powszechnie znany program do projektowania. Jego nazwę zachowamy w tajemnicy. Należy dodać, że nie robiliśmy nic, aby pogorszyć wygląd kodu. Przepis: brzoskwinie w s y r o p i e < / t i t l e x m e t a httpequi v= "Con ten t -Type "content "text /html;
charset=iso-8859-l"x/HEADxbody bgcolor="#FFFFFF" t e x t = " # 6 6 6 6 6 6 " link="#CC3300" vlink="#CC3300" alink-"#CC3300">
colspan="5"xbxfont face="sans-serif" s i z e = " 2 " color="#DDAODD">Brzoskwinie w syropie
width="50" height="l"x/tdx/tr>
< b x i > S k ł a d n i k i < / i x / b > < / f o n t x / t d >
Rozdział 14.
»
Styl PHP__________________________________________253
D u ż e b r z o s k w i n i e < / f o n t x / t d >
colspan="2"xfont size="l" face="sansserif " > 6 & n b s p ; < / f o n t x / t d >
width="51"
height="l"x/tdx/tr>
Białe w i n o < / f o n t x / t d >
Świeży imbir
2 s n b s p ; < / f o n t x / t d >
plastry 
height="l"x/tdx/tr>
254_________________________________________Część l »
Podstawy PHP
i,nbsp; < / t d >
Przygotowanie
l. Łnbsp; < / f o n t x / t d > W r z u ć brzoskwinie na 15 sekund do wrzącej wody, ułatwi to obranie ze skórek. Ostrożnie p r z e k r ó j na pół, usuwając pestkę. snbsp;
2 . Snbsp; Wrzuć wszystkie składniki oprócz brzoskwiń do dużego rondla. Gotuj aż do rozpuszczenia cukru. snbsp:
face="sans-serif" valign="top">3 . Snbsp; < / f o n t x / t d > Gotuj brzoskwinie w syropie na wolnym ogniu przez 15 minut. Obracaj co 5 minut. Podawaj cieple, polanę syropem
. Snbsp:
Próba dodania PHP do takiego pliku HTML może być źródłem problemów. Jeżeli jed-
nak chcesz to robić pamiętaj, że nie jest to wina PHP i skieruj swoje żale do innego producenta. Spróbujemy jednak znaleźć jakąś radę dla tych, którzy nie potrafią uwolnić się od narzędzi graficznych.
Prawdopodobnie najlepsze, co możesz zrobić, to przepuszczenie wygenerowanego kodu HTML przez program, który uczyni go bardziej czytelnym dla człowieka. Nie trwa to zbyt długo, a może wyraźnie poprawić sytuację. Jednym z lepszych narzędzi tego typu jest HTML Tiddy dla Unixa, który można znaleźć pod adresem:
http ://www. w3. org/People/Raggett/tidy/
Program ten naprawia częste błędy w kodzie HTML, takie jak brakujące znaczniki zamykające. Poza tym posiada (na razie niewielkie) możliwości współpracy z PHP, jeżeli używamy standardowych znaczników . Można więc naprawić sytuacje, gdy „tak się śpieszyłem, że zapisałem dokument Microsoft Office jako HTML i dodałem kilka fragmentów w PHP". Program ten odczytuje dokumenty Microsoft Office zapisane jako HTML, mimo że w chwili pisania książki HTML Tiddy nie był dostępny na platformie Windows. Nieco bardziej pracochłonnym, ale dającym precyzyjniejszą kontrolę podejściem jest użycie analizatora poprawności HTML. Narzędzie to (często jest dostępne w sieci)
Rozdział 14.
»
Styl
PHP__________________________________________255
wylicza wszystkie miejsca w dokumencie, w których kod nie jest zgodny ze standardem HTML. W przeciwieństwie do HTML Tiddy, nie poprawia kodu, trzeba samemu punkt po punkcie wprowadzić zmiany. Kolejną efektywną metodą zwiększenia czytelności kodu jest kupno dobrego pakietu zawierającego zarówno dobre narzędzie wizualne, jak i dobry edytor tekstowy. Nie jest to reklama, ale znanym programem spełniającym te warunki jest Macromedia Dreamweaver. Działa na Macach i pod Windows, posiada obsługę PHP i może współpracować z wieloma programami obróbki obrazu. Nawet projektanci PHP, którzy piszą cały kod ręcznie, mogą sobie pomóc, wybierając
dobry edytor tekstowy (mówiliśmy o tym w rozdziale 3.). Po co marnować czas na zamykanie znaczników HTML, czy szukanie brakujących nawiasów? Większość dzisiejszych edytorów tekstu potrafi automatycznie domykać znaczniki i nawiasy, co pomaga uniknąć trywialnych błędów. Na pewno znajdziesz taki program, na odpowiednią platformę, który można dostosować do potrzeb. Niektórzy uwielbiają wielokolorowe podświetlanie składni, inni uważają to
za zupełnie niepotrzebne. Niektórzy używają do wcięć tabulatora, a inni spacji, niektó-
rzy lubią programy, które potrafią robić wszystko oprócz kawy, inni żądają prostego, ale posłusznego narzędzia. Możesz skonfigurować prawie każdą kombinację funkcji, ale musisz poświęcić trochę czasu na ustawienie edytora. Ponieważ edytor dla programisty jest jak koń dla rycerza, czasu nie zmarnujesz. Upewnij się, że twój edytor jest zgodny z programami twoich współpracowników. Niektóre edytory usuwają wcięcia wykonane za pomocą tabulacji (dokumenty wyglądają brzydko), używają dziwnych apostrofów itp. Twoi koledzy nie będą zachwyceni, jeżeli będą musieli od nowa formatować każdą obejrzaną przez ciebie stronę.
Niektórzy nie potrafią zaakceptować faktu, że pamięć w komputerze nie jest bezcenna.
Spędzają mnóstwo czasu na próbach zacieśnienia tekstu programu tak, aby zajmował
możliwie mało miejsca. Praktyka ta jest niestety wspierana przez niektóre książki techniczne oraz wydawców czasopism, którzy żądaj ą od autorów, aby używali różnych sposobów ograniczenia długości wydruków programów (jak w poniższym przykładzie). 0) { if($Horse=="Man O'War") print("Kasztan, białe plamki"); elseif($Horse=="Native Dancer") print("Jasnoszary"); elseif($Horse=="Seattle Slew") print("Czarny"); ) else {
print{"Spróbuj jeszcze raz."); }?>
W przykładzie użyto nawiasów klamrowych w stylu Kernighana i Ritchie, wcięcia mają tylko jedną spację na poziom, brak powtarzalnych, ale znaczących elementów pliku (nagłówków HTML) i po prostu przestrzeni. Wszystko jest na pozór w porządku, ale czytelność pozostawia wiele do życzenia. Porównaj ten format z poniższym i wyobraź sobie oba fragmenty wbudowane w dłuższy i bardziej skomplikowany skrypt, który musisz szybko zmodyfikować:
Początkujący programiści powinni zapamiętać, że kod w książkach, a szczególnie
w Internacie (gdzie miejsce naprawdę nic nie kosztuje) nie musi testować ludzkiej zdolności do zrozumienia źle zapisanego tekstu.
Na koniec należy wspomnieć, że staranność również się liczy. Staje się szczególnie ważna, gdy liczba współpracujących ze sobą programistów wzrasta i coraz ważniejsze stają się zagadnienia łatwości konserwacji.
Komentarze Wstawianie komentarzy do kodu jest często porównywane do czyszczenia zębów za pomocą nitki: ważne dla zdrowia i higieny, ale zbyt często pomijane „tylko tym razem". Problem tkwi w tym, że nie ma natychmiastowych korzyści ze stosowania komentarzy — wszystkie ich zalety są dostrzegane po długim czasie. Spróbuj sobie przypomnieć, kiedy słyszałeś kolegę z sąsiedniego pokoju, zachwycającego się pięknym komentowaniem kodu przez innego programistę. Niewiele dynamicznych witryn WWW zatrzymuje się na chwilę, aby programiści mogli umieścić końcowe komentarze w tekście skryptów. Co powinno być skomentowane? + Wszystko, co w przyszłości może powodować pytanie: „o czym ja wtedy myślałem?". Zwykle fragmenty zawikłane lub napisane niestarannie. * Wszystkie fragmenty, które mogą nie być nieprawidłowe za jakiś czas (na przykład używane magiczne liczby). * Wszystko, co nieprawidłowo użyte może powodować błędy. Idealnie byłoby, gdybyś uwzględniał przy komentowaniu następujące elementy: * datę utworzenia pliku i nazwisko twórcy; 4 datę ostatniej zmiany i nazwisko modyfikującego oraz opis powodów zmiany; * inne pliki i programy zależne od istnienia tego pliku; * zakładane przeznaczenie pliku oraz jego części składowych; 4 notatki, które chciałbyś umieścić w pisanej później dokumentacji;
Rozdział 14.
*
Styl PHP__________________________________________257
+ powody zachowania niektórych nieużywanych fragmentów (alternatywne wersje, kopie archiwalne itp.), warunki ich usunięcia lub inne plany. Oczywiście to ty decydujesz, które elementy są naprawdę niezbędne. Jeżeli używasz PHP do obsługi bardzo małej, osobistej witryny, prawdopodobnie komentowanie będzie
zbędne, ale im bardziej zwiększają się objętość i stopień skomplikowania witryny, tym większa jest potrzeba opisywania pracy. Teoretycznie jest możliwe przekomentowanie kodu, ale w praktyce niewielu programistów jest w stanie to zrobić.
W rozdziale 5. opisaliśmy kilka dostępnych stylów komentarzy w PHP. Pamiętaj, że żaden z nich nie będzie widoczny w komputerze klienta. Jeżeli chcesz umieścić na stronie czytelny dla klienta ukryty tekst, musisz użyć komentarzy HTML.
Nazwy zmiennych i plików Niektórzy uważają wymyślanie nazw zmiennych za pisanie poematu epickiego. Pracowaliśmy kiedyś z osobą, która wydawała się niezdolna do wymyślenia nazwy, ani nawet przyzwoitego schematu nazwy. Pliki tworzone przez tę osobę miały nazwy
tworzone przez dodanie kolejnego numeru: filel6.html, filel7.html, filel8.html itd. Wszystkie nazwy zmiennych na stronie WWW miały nazwy varl, var2 itd. Historia ta byłaby zabawniejsza, gdyby zdarzyła się komuś innemu. Ponieważ w PHP używa się o wiele więcej zmiennych niż w HTML, powinieneś opracować wydajny schemat nazywania zmiennych na wszystkie okazje. W dalszej części
rozdziału przedstawimy kilka wskazówek.
Krótkie lub długie Dłuższe nazwy są lepsze, ponieważ niosą więcej informacji. W razie potrzeby możesz podzielić długie nazwy za pomocą znaków podkreślenia lub wielkich liter.
Nawet jeżeli większość systemów plików pozwala na używanie drugich nazw, to katalog taki oglądany jako ikona nie wygląda dobrze. Użytkownicy GUI mogą być świadomie lub nieświadomie uprzedzeni do używania długich nazw. Etykiety ikon są zwykle
krótkie i to powoduje tendencję do używania bardzo zwięzłych nazw plików. Spróbuj nadać plikowi długą i skomplikowaną nazwę (np.: PrzepisBrzoskwinieWSyropie.php) i umieść go na pulpicie — nie wygląda to najlepiej.
Większość plików, używanych w systemach graficznych, może mieć nazwy ze spacjami (np.: Moje Dokumenty.doc). Unix w teorii również na to pozwala, ale w praktyce nie jest to najlepszy pomysł. Mimo że PHP stara się działać również z takimi plikami, w niektórych sytuacjach może to być niemożliwe.
258_________________________________________Część l
» Podstawy PHP
Jedną z zalet stosowania PHP do dynamicznego generowania zawartości stron jest możliwość skrócenia nazw plików, które są rozszerzane i rozróżniane przez ciągi zapytań, w stylu metody GET. Witryna statyczna musi używać nazw jednoznacznie identyfikujących każdą stronę, np.: FeatureHitchcockBirds.html MiniseriesIrvinSpy.html
Witryna dynamiczna może identyfikować te same strony za pomocą: feature.php?ID=l
miniseries.php?ID=2
W tej sytuacji możesz korzystać z zalet obu rozwiązań: krótkich nazw plików i jednoznacznej identyfikacji. PHP nie ogranicza długości nazw zmiennych, więc możesz tworzyć długie, ale niosące dużo danych nazwy, jak np. $AdcłressOfCli v entCompanyInSasketchewan. To twoje
skrypty. Musisz jedynie ostrożnie stosować zmienne o długich nazwach jako fragmenty formularza, obsługiwanego za pomocą metody GET.
Podkreślenia lub wielkie litery Najczęściej stosuje się dwa sposoby dzielenia długich nazw zmiennych lub nazw plików w Uniksie. Długa nazwa podzielona podkreśleniami wygląda następująco: $name_of_favorite_beer
Jeżeli użyjemy wielkich liter, ta sama nazwa wygląda w następujący sposób: $NameOfFavoriteBeer
Wewnętrzne duże litery powodują, że nazwa posiada „garby", dlatego ten sposób konstruowania nazw jest często nazywany wielbłądzim. Wybór sposobu należy do ciebie. PHP stosuje w predefiniowanych zmiennych podkreślenia ($PHP_SELF). Pamiętaj, że nie możesz używać myślników jako znaków rozdzielających i uważać, stosując kropki. W nazwach plików systemu Unix wielkie i małe litery były rozróżniane zawsze. Nazwy plików w innych systemach operacyjnych mogą ignorować wielkość liter. Jeżeli będziesz przenosił pliki PHP pomiędzy systemami, musisz to robić bardzo uważnie.
Najważniejszą rzeczą, o którą musisz zadbać, jest konsekwencja. Bardzo irytujące są sytuacje, gdy usiłujesz zorientować się, dlaczego zmienna $My_Number nie została zainicjowana, i odkryjesz, że wcześniej przypisywałeś wartość do zmiennej o nazwie SMyNumber.
Rozdział 14.
»
Styl PHP_______________________________________259
Powtórne wykorzystanie zmiennych Istnieją sytuacje, gdy należy rozmyślnie używać tej samej nazwy, zamiast nową nazwę
zmiennej tworzyć za każdym razem. Chcesz, aby zmienna używana do określonego typu zadania miała zawsze poprawną wartość. Musisz być pewien, że nie będzie proble-
mu z rozróżnieniem, które z dwóch zapytań jest właśnie wykonywane, jeżeli używasz tej samej nazwy dla obu (np.: $query). PHP zmieni starą wartość na nową i zmienna będzie zawsze prawidłowa.
Łatwość konserwacji Weterani programowania twierdzą, że łatwość konserwacji jest najważniejszą z zalet. Niestety głównym problemem jest to, że łatwość konserwacji jest zwykle w konflikcie z innymi celami, najczęściej z wydajnością. W czasach Internetu zdarza się, ktoś inny konserwuje nasz kod, wydaje się więc, że widać zwycięzcę tego konfliktu.
Najważniejsze zasady, o których powinieneś pamiętać, to: * fragmenty, które będą często zmieniane, muszą być łatwe do odszukania; ** zmiana tych fragmentów nie powinna nieść ze sobą nieprzewidzianych efektów;
* każda zmiana powinna być wykonywana tylko w jednym miejscu.
Unikaj „magicznych liczb" Magiczną liczbą nazywamy wartość numeryczną, która pewnego dnia będzie zmieniana, a jest ukryta głęboko we wielu miejscach kodu. Wyobraź sobie taki fragment kodu w witrynie WWW hipotetycznego banku:
print("Oprocentowanie lokaty może wynieść nawet 15,5 ! ");
$przyklad_wklad = 5000 * 1.155; printC'Po roku możesz z inwestycji 5000 zł uzyskać $przykład_wklad! ");
Gdy oprocentowanie zmieni się, np.: 15%, ktoś będzie musiał znaleźć i zmienić miejsca, w których ta wartość występuje. Podczas szukania w tekście wartości 15,5 bardzo łatwo opuścić wartość 1.155 w drugim wierszu przykładu. Spowoduje to prezentację nieprawdziwych danych. Dla prostych witryn lepszym rozwiązaniem jest użycie zmiennej $oprocentowanie, która jest inicjowana na samym początku skryptu — zmiana oprocentowania powoduje jedynie zmianę wartości tej zmiennej. Bardziej skomplikowane witryny mogą tworzyć
strony, wywołując odpowiednie funkcje, ze zmienną typu $oprocentowanie jako parametrem wywołania. Zawartość niektórych witryn zapisana jest w bazie danych, więc nie trzeba w nich zmieniać ani jednego fragmentu kodu.
260_________________________________________Część l
»
Podstawy PHP
Funkcje Po próbach prowadzenia złożonej witryny WWW, która używała języka skryptowego nieposiadającego funkcji, możemy powiedzieć, że funkcje pełnią kluczową rolę w pielęgnacji oprogramowania. Sztuka stosowania abstrakcji proceduralnej przy użyciu funkcji może być opisana w osobnej książce. Przytoczymy tylko krótkie wskazówki. * Musi istnieć powód przeniesienia fragmentu kodu PHP do funkcji, szczególnie w przypadku wielokrotnego użycia tego kodu. •* Pisz krótkie definicje funkcji. Jeżeli funkcja zbytnio się rozrasta, podziel ją na mniejsze funkcje. •* Funkcja musi być zdefiniowana przed użyciem. Kolejność funkcji nie ma znaczenia.
Pliki dołączane Jedną z największych przewag dynamicznych stron WWW nad statycznym HTML jest zdolność zmniejszania redundancji. Każdy, kto kiedykolwiek zarządzał statyczną witryną dowolnych rozmiarów, wie, jak wiele stałych fragmentów znajduje się na stronie — zmiana każdego znaku nie jest prosta, jeżeli witryna ma 200 stron. PHP ułatwia wstawianie dowolnych fragmentów do skryptów, od jednego znaku, do całych oddzielnych programów, używając wbudowanych funkcji include lub requ-
ire. Składnia jest bardzo prosta:
Można również użyć zmiennych nazw plików w następujący sposób:
Fragment ten spowoduje włączeniem do pliku Park.inc. Na rysunku 14.1 zamieszczony jest przykład strony PHP używającej dołączanych plików. Możesz używać dowolnych rozszerzeń dołączanych plików. Zwykle stosowane są . txt, . inc lub nawet . htral.
Należy pamiętać o tym, że: * PHP włącza cały tekst pliku do skryptu PHP w trybie HTML (wyjaśnialiśmy to w rozdziale 4.). Jeżeli włączany plik ma być analizowany przez PHP, należy użyć znaczników PHP na początku i końcu. Jeśli dowolny fragment włączanego pliku ma być przetwarzany przez PHP, część ta musi być otoczona znacznikami PHP.
261
Rozdział 14. » Styl PHP Rysunek 14.1.
Plik PHP z włączanymi plikami
* Przypomnij sobie różnice (szczegółowo opisane w rozdziale 5.) pomiędzy funkcją include, a konstrukcją require (dużo szybszej w PHP 4). W PHP 4 można również stosować nową funkcję include__once ( ) , która może zmniejszyć czas ładowania strony, gdy pliki włączane są wiele razy. + Funkcja include może być używana do tworzenia skomplikowanych stron WWW z plików tekstowych zamiast z bazy danych. W niektórych przypadkach działa o wiele szybciej. Jeśli zadasz sobie trud utworzenia połączenia z bazą danych, otrzymasz doskonałe narzędzie do przechowywania dużych bloków tekstu. Poniższy przykład ilustruje użycie wielu funkcji include na jednej stronie:
< !-- Jeżeli chcesz, umieść ten nagłówek w włączanym pliku. --> Menu dnia
Dzisiejsze menu
262_________________________________________Część
l
»
Podstawy
PHP
Moje ulubione:
?>
Moje u l u b i o n e < / H l >
< P > T u t a j mam k i l k a moich ulubionych r z e c z y , < / P >
CLASS="topic">KSIĄŻKK/DIV>
Cryptonomicon, autor: Neal Stephenson
Majstersztyk dla technicznych — to nasze życie, wejdź w kierat ogromnych inwestycji. Załaduj esej "Na początku byi wiersz komend" z witryny:
www.crytonomicon.com
MUZYKA
When The Pawn..., Fiona Apple
Jeszcze jedna latynoska gwiazdka.
Wydruk 21.5. Dołączany plik nawigacyjny (navbar.inc)_______________________________ •CTABLE W I D T H = 1 0 0 % CELLPADDING=10XTR>
Wydruk 21.6. Dołączany plik arkuszy stylu (style, inc)_________________________________
Wprowadzanie danych przez HTTP Prosty dziennik jest odpowiedni do wielu zastosowań, ale ma jedną wadę: nie możesz tworzyć pozycji dziennika poprzez sieć WWW. W zamian musisz stworzyć każdą pozycję używając edytora tekstowego, np. Emacs czy Notepad i zapisać w katalogu dokumentów serwera WWW. Może to będzie problemem, jeżeli nie możesz zastosować połączenia telnet, ssh lub ftp albo niezbyt dobrze wiesz, jak to zrobić. Dlatego następnym logicznym krokiem dla wielu użytkowników jest użycie HTTP. Za pomocą PHP możesz stworzyć dobre formularze do wprowadzania danych oraz strony je wyświetlające. Jedynym poważnym problemem jest konieczność nadania uprawnień do odczytu i zapisu dla użytkownika HTTP (zwykle jest to Nobody lub Everybody). Jest to niebezpieczny proces i nie polecamy go. Opisujemy tutaj skrypt wprowadzania danych, więc możesz zapoznać się z nim, zanim przejdziemy do lepszego rozwiązania, jakim jest użycie bazy danych zamiast oddzielnych plików dla każdej pozycji. Spróbujemy w minimalnym tylko stopniu zająć się problemami bezpieczeństwa, używając hasła i wysyłając e-mail przy próbie nieautoryzowanego dostępu.
Ekrany wyświetlania danych są dokładnie takie same jak w tworzonej lokalnie wersji dziennika. Dodatkowo potrzebuj emy plików zamieszczonych na wydrukach 21.7 do 21.10.
login.php logentry.php
logentry_handler.php password, inc Umieśćmy plik password, inc w katalogu poza drzewem dostępnym przez WWW, na przykład /home/weblog. Katalog ten musi byś dostępny dla wszystkich, a użytkownik
httpd (Nobody) musi mieć możliwość odczytania pliku. Jeżeli posiadasz prawa administratora, możesz zmienić właściciela pliku na użytkownika httpd. Jeżeli nie, musisz nadać uprawnienia do odczytu wszystkim, co stanowi osłabienie systemu bezpieczeństwa. Upewnij się, że hasło to nie jest hasłem użytkownika systemowego.
Wydruk 21.7. Logowanie do formularza wprowadzania danych (login.php)___________________
Wydruk 21.9. Ekran wprowadzania danych (logentry.php)______________________________
Ekran wprowadzania danych do dziennika
else
{
?>
mail("meSlocalhost", "Podglądanie dzinnika", "Ktoś z adresu $REMOTE_ADDR próbuje wejść na twoją stronę wprowadzania danych do dziennika."); )
Wydruk 21.10. Skrypt obsługujący formularz (logentryjiandler.php)_____________________
$try_entry = fwrite($fp, "Slogtext"); print("Wprowadzona pozycja dziennika na dzień Sdate zawiera Stry_entry znaków.");
else
?>
} ( mail("meSlocalhost", "Podglądanie dziennika, część 2.", "Ktoś z adresu SREMOTE_ADDR próbuje wejść na twoją stronę wprowadzania danych do dziennika."); }
370______________________________________Część II » PHP i bazy danych
Dołączenie bazy danych Po wypróbowaniu dopisywania pozycji za pomocą HTTP i funkcji PHP zapisującej plik już tylko mały krok do przechowywania pozycji w bazie danych, a nie w osobnych plikach tekstowych. Jest to bardziej staranne — ważne w rozwijających się witrynach — i wyraźnie bezpieczniejsze. Poza tym możesz nadać różne uprawnienia różnym użytkownikom, co pozwala na bezpieczną pracę wielu redaktorom pracującym nad zawartościom witryny. Użycie bazy danych ma jeszcze dwie dodatkowe zalety. Po pierwsze, można łatwo napisać skrypt do edycji i wprowadzania pozycji dziennika za pomocą formularza HTML. Jeszcze lepsze jest programowe, a nie ręczne tworzenie łączy do nawigacji pomiędzy pozycjami dziennika. Mimo że mają podobne nazwy i funkcje, pliki zamieszczone na wydrukach 21.11 do 21.17 są nieco inne od poprzedniego zestawu. Potrzebujemy również skryptu tworzącego bazę danych (chyba że zrobisz to za pomocą wiersza komend MySQL), jeżeli chcesz zmieniać poprzednie pozycje, musisz dodać skrypt o nazwie dbjogedit.php. Większość z tych skryptów nie zachowuje się elegancko, jeżeli baza danych nie zawiera danych, szczególnie nazw użytkowników i haseł w tabeli login. Dopóki nie umieścimy jakiegoś rekordu w tej tabeli, całość programu nie działa. Chcieliśmy skupić się na głównych funkcjach, a nie na kontroli błędów, ponieważ występuje tu wiele miejsc, w których powinno się sprawdzać, czy tabela nie jest pusta. Wydruk 21.11. Ekran logowania do bazy danych dziennika (db_login.php)_______
Ekran logowania do dziennika
Zaloguj się t u t a j , aby dopisać nową pozycję.
Załoguj się t u t a j , aby zmienić poprzedna p o z y c j ę .
$query = ("UPDATE mylog SET logtext = 'Slogtext1 WHERE date = '$edit_date'"); $result = mysql_query(Squery); print("Wynik zmiany: 5result."); }
(
?>
m a i l ( " m e @ l o c a l h o s t " , "Podglądanie dzinnika część 2", "Ktoś z adresu SREMOTE_ADDR próbuje wejść na twoją stronę zmiany danych do d z i e n n i k a . " ) ; )
Wydruk 21.16. Główny szablon dziennika na podstawie bazy danych (db_weblog.php)
Rozdział 21.
Dotarłeś do strony poprzez łącze, więc znana jest data. Nie jest to pierwsza ani ostatnia pozycja w bazie.
2.
Dotarłeś do strony poprzez łącze, więc znana jest data. Jest to pierwsza pozycja w bazie.
3.
Dotarłeś do strony poprzez łącze, więc znana jest data. Jest to ostatnia pozycja w bazie.
4.
Oglądasz tą stronę bez podawania daty (wiec domyślnie jest data dzisiejsza)
i jest to nowa pozycja dzisiaj. 5.
Oglądasz te stronę bez podawania daty (więc domyślnie jest data dzisiejsza) i nie jest to nowa pozycja. Daj domyślny komunikat z łączem do ostatniej pozycji.
*/ /* Pobierz dzisiejszą datę dla przypadków 4 i 5. */
if{llsSet(Sdate)) l $date = datę("Ymd"); } ?>
Dziennik sieciowy PHP4:
Mój dziennik na dzień
/* Otwórz połączenie do bazy danych. */ include("/home/weblog/db_password.inc"); mysql_connect($hostname, Suser, Spassword); mysql_select_db("weblogs"); /* Odszukaj ostatnią pozycję dla przypadków 3, 4 i 5. */
/* Pierwsza gałąź tekstu wyświetla pozycje dziennika w przypadkach l - 4... */
$queryl = ("SELECT ID, logtext FROM mylog WHERE date = Sdate"); $resultl = mysql_query($queryl); $row_test_num = mysql_num_rows(Sresultl); if($row_test_num > 0) f Sentry_row = mysql_fetch_array($resultl);
$entry_ID = $entry_row[0]; $logtext = stripslashes($entry_row[1]); /* Pobierz poprzednią datę dla przypadków l, 3 i 4. Ten test zakłada, że baza zwiększa wartości od 1; jeżeli jest inaczej, powinieneś zmienić liczbę poniżej. */ if($entry_ID > 1) t
$prev_ID = $entry_ID - 1;
$query2 = ("SELECT date FROM mylog WHERE ID = $prev_ID"); $result2 = mysql_query(Squery2);
Możliwe rozszerzenia Możesz zmienić i dodać następujące elementy w przytoczonym kodzie: + Zmiana kolorów, stylów i układu. •* Zmiana częstotliwości uaktualnień (co tydzień, co miesiąc). •* Zmiana nawigacji na bazującą na kalendarzu, a nie na łączach Następny i Poprzedni.
+ Zmiana nawigacji na tematyczną, a nie na podstawie daty. + Wstrzymanie automatycznego przeterminowania pozycji. + Umożliwienie edycji przyszłych pozycji w bazie danych. • Dodanie wielu autorów, redaktorów z różnymi uprawnieniami. Oprócz osobistego dziennika, możesz na podstawie tego kodu utworzyć dowolną prostą chronologiczną witrynę, na przykład: •* Rodzinny dziennik wakacyjny.
•* Historia projektu.
376____________________________________Część
II
»
PHP
i
bazy
danych
+ Opowieść o utracie wagi dzięki heroicznej diecie i ćwiczeniom. •* Kronika ciąży i rozwoju dziecka.
Podsumowanie Mimo że PHP jest użyteczny w małych oddzielnych projektach, takich jak głosowania, najbardziej imponujące jest tworzenie kompletnej witryny sterowanej danymi. Naj-
prostszym przykładem takiej witryny jest osobisty dziennik sieciowy. Polecamy prowadzenie takiej witryny każdemu użytkownikowi, ponieważ jest użyteczna do testowania nowych pomysłów i technik.
Jeżeli chcesz, możesz przechowywać dane w zwykłych plikach tekstowych, używając PHP do dołączenia tych plików do szablonu na podstawie jakiegoś kryterium, na przykład daty. Będzie to dużo lepsze niż statyczny HTML i może zaoszczędzić trochę czasu przy formatowaniu, kosztem nieco obniżonego bezpieczeństwa. O wiele lepiej jest jed-
nak przechowywać dane w bazie danych.
Format dziennika sieciowego jest bardzo elastyczny. Może zostać rozbudowany do poważnej publicznej witryny, jak na przykład Slashdot (z wieloma współpracownikami i fachową redakcją zawartości). Możesz również tworzyć mały sekretny pamiętnik. Ważne jest, że po stworzeniu za pomocą PHP kompletnej witryny sterowanej danymi
nie wrócisz już do statycznych stron WWW.
Rozdział 22.
Sieciowe głosowanie W tym rozdziale: * Przykład zastosowania PHP i bazy danych
+ Zbieranie głosów * Wyświetlanie głosów * Nadużycia Rozdział ten jest przeglądem części kodu PHP, który jest używany w popularnej witrynie WWW. Jest to dodatkowo fragment programu, który w przeciwieństwie do prezentowanych do tej pory przykładów jest ciągle rozwijany. Pokazuje on dosyć skomplikowaną interakcję z bazą danych, sposób zastosowania mechanizmu cookie oraz kilka interesujących sztuczek i technik. Chociaż do tej pory staraliśmy się zamieszczać czyste i niezależne przykłady, w tym rozdziale zdecydowaliśmy się na fragment prawdziwego programu. Ponieważ pokazujemy tylko część kodu działającego w naszej witrynie, ten pokazany na wydrukach sam nie będzie funkcjonował W rozdziale tym założyliśmy znajomość zawartości całej drugiej części książki, użyliśmy technik opisanych w rozdziale 26. „Cookie i HTTP". Możesz zapoznać się najpierw z rozdziałem 26., albo przeczytać niniejszy, wierząc nam na słowo, że to, co napisaliśmy o cookie, jest prawdą.
Zadania systemu W „wolnym czasie" Autorzy uruchomili kilka witryn WWW z recenzjami i rekomendacjami książek. Jedna z nich jest poświęcona kryminałom (www.mysteryguide.com), druga opisuje książki popularno-naukowe (www.siencebookguide.com).
378_______________________________________Część II »
PHP i bazy danych
Nasi recenzenci i my wypowiedzieliśmy się na temat książek, pozwoliliśmy również naszym czytelnikom na ocenę za pomocą not od l do 5. Mimo że jest to czysto naukowy pomiar, nasi czytelnicy dobrze się przy tym bawią. W rozdziale tym zajmiemy się kodem PHP użytym do zbierania i wyświetlania ocen wystawionych przez naszych czytelników.
Cele systemu Gdy rozpoczynaliśmy dodawanie tych funkcji do naszej witryny, zamierzaliśmy zrealizować kilka celów. Chcieliśmy, aby nasz system: * pozwalał ocenić książkę na stronie recenzji; * wyświetlał bieżącą ocenę książki na stronie; * na głównej stronie wyświetlał ranking książek; * pozwalał na łatwe jednorazowe głosowanie na książkę; ** nie pozwalał na wielokrotne głosowanie na tę samą książkę.
Ostatnie dwa punkty (łatwość użycia i zniechęcanie do zniekształcania wyników) wymagają krótkiego opisu. Mimo że w tym czasie nie wiedzieliśmy, że określenie to będzie częścią sporu patentowego, chcieliśmy, aby głosowanie odbywało się ,jednym kliknięciem". Chcieliśmy, aby użytkownik mógł po prostu zagłosować za pomocą jednego kliknięcia, zamiast wypełniać formularz i naciskać przycisk Wyślij. Po drugie chcieliśmy, aby normalny użytkownik systemu głosowania miał utrudnione wielokrotne głosowanie na swoje ulubione pozycje. Wiemy, że bardzo trudno całkowicie uszczelnić system tak, aby żaden żartowniś nie mógł obejść zabezpieczeń. Zastosowaliśmy system bazujący na mechanizmie cookie i spowodowaliśmy, że jeden użytkownik może tylko raz zagłosować na książkę. Dodatkowo uruchomiliśmy system odrzucania głosów, które w sposób oczywisty są zniekształcaj ą wynik.
Struktura Nasza witryna ma jedną stronę zarezerwowaną dla każdej omawianej książki. We wcześniejszej wersji witryny każda taka strona była statyczną stroną HTML. W wersji późniejszej każda strona jest dynamicznie generowana na podstawie zawartości bazy danych MySQL. Sam kod składa się z dwóch części: kodu obsługującego zbieranie i wyświetlanie ocen oraz kodu obsługującego centralną stronę ocen czytelników. W rozdziale tym te fragmenty kodu są opisane w częściach „Zbieranie głosów" oraz „Wyświetlanie zbiorczych wyników".
Obsługa bazy danych We wszystkich przykładach zamieszczonych w tym rozdziale wykorzystujemy bazę danych MySQL. Mimo że mamy wiele różnych tabel do obsługi całej witryny, w tych przykładach używamy tylko dwóch o następującej strukturze:
Tabela 'book' ID int (NOT NULL, PRIMARY KEY, AUTO INCREMENT)
title varchar(75) [... wiele kolumn nie używanych w tym kodzie]
Tabela 'ReaderRatings' ID int (NOT NULL, PRIMARY KEY, AUTO INCREMENT) bookid int (NOT NULL)
Zbieranie głosów Pierwszy fragment kodu jest odpowiedzialny za części strony związane z głosowaniem. Jest to fragment umożliwiający głosowanie oraz ten, który zawiera wyniki głosowania na książkę. Na rysunku 22.1 pokazano część strony umożliwiającą głosowanie — aby zobaczyć całą stronę, możesz zajrzeć na witrynę \vww. mysteryguide.com lub www.siencebookguide. com. Rysunek 22.1.
Fragment strony umożliwiający
głosowanie
Fragmenty strony odpowiedzialne za głosowanie wyświetlają:
380_______________________________________Część II » PHP i bazy danych
* zaproszenie do głosowania i podsumowanie głosów, jeżeli użytkownik jeszcze nie głosował na tę książkę;
* tekst „Dziękujemy za głosowanie", jeżeli użytkownik już zagłosował; ** puste miejsce, jeżeli wykryjemy za pomocą mechanizmu cookie, że użytkownik już zagłosował na książkę. Wyświetlaniem tych fragmentów strony oraz obsługą przesłanych głosów zajmują się
funkcje pokazane na wydruku 22.1. Są one dołączone do pliku „book.php", który zajmuje się wyświetlaniem stron poszczególnych książek. Wydruk 22.1. Funkcje wyświetlania strony z informacjami o książce_______________________
$dbhost, $dbuser, $dbpass,
1 and book.id = bookid group by bookid order by avgrating asc, countrating desc"); print("
KsiążkaLiczbaŚrednia
");
Scounter = 0; w h i l e ( ( S r o w _ a r r a y = mysql_fetch_row(SresultID)) ss ($counter < $max_rating_display)) f if ( ( $ r o w _ a r r a y [ l ] > $rain_worst_votes - 1) SS
( 3 r o w _ a r r a y [ 4 ] != S r o w _ a r r a y [ 3 ] ) )
386____________________________________Część II » PHP i bazy danych
SresultlD = mysql_query("select avg(Rating) as avgrating,
Count(ReaderRatings.ID) as countrating, book.id, book.title from ReaderRatings, book where BogusBit <> 1 and book.id = bookid group by bookid order by countrating desc"); print("
&tt!69 1999 Troutworks, Inc. All rights reserved. Ciagle zmieniane
Rysunek 22.2
Strona wyświetlania wyników
Kod ten wyświetla trzy tabele typu „Złota dziesiątka", zawierając najbardziej popularne, najmniej popularne oraz najczęściej oceniane książki. Stylistycznie rzecz ujmując, powtarzanie kodu dla każdej tabeli jest nieładne — właściwie to realizując, powinniśmy napisać funkcję, która jako argument wymagałaby podanie typu tabeli i kolejności sortowania. Niestety nie zrobiliśmy tego i pokazujemy kod w takiej postaci, w jakiej istnieje.
Rozdział
22.
*
Sieciowe
głosowanie__________________________________387
Nadużycia i skalowanie System naszkicowany w tym rozdziale jest wystarczający do zbierania i wyświetlania
głosów w naszych witrynach poświęconych książkom i odpowiada użytkownikom. W dodatku bazujący na cookies system utrudniający wielokrotne głosowanie na tę samą książkę wydaje się być wystarczający. Proszę nie mylić utrudniania z zabezpieczaniem — na pewno nie zgodzisz się na przeprowadzanie w ten sposób wyborów prezydenckich. Istnieje wiele sposobów na ominięcie tego zabezpieczenia. Zauważyliśmy, że
wielu użytkowników zaakceptowało sens użycia tej funkcji. Czasami musimy wyrzucić część podejrzanych głosów, które są w sposób oczywisty wygenerowane przez skrypt lub ręcznie. Nie wnosi to niczego oprócz marnowania naszego czasu.
Jeżeli chodzi o skalowanie, to tylko jedna z naszych witryn (wmv.mysteryguide.com) jest wystarczająco często odwiedzana, aby obsłużyć odczuwalną liczbę głosów. Do tej pory zebraliśmy około 10000 głosów. Jest to trywialne zadanie dla każdej przemysłowej bazy
danych i mamy przyjemność zakomunikować, że nasza, warta 400 dolarów, maszyna K6,
służąca za serwer WWW, zapewnia obsługę zagregowanych stron za pomocą zestawu Linux, Apache, MySQL i PHP. Nie stwierdzamy żadnych zauważalnych opóźnień, mimo że
nie zastosowaliśmy żadnego buforowania ani optymalizacji bazy danych.
Podsumowanie W tym rozdziale pokazaliśmy bardziej skomplikowany fragment kodu, który jest używany przez dosyć popularną witrynę WWW. Zbiera on głosy użytkowników na temat jakości książek przedstawionych w witrynie, zapisuje głosy w bazie danych i wyświetla zestawienie ogólne i dla danej książki. Witryna używa systemu cookie utrudniającego
sztuczne windowanie wyników.
W dwóch kolejnych rozdziałach zajmiemy się bardziej ogólnymi aspektami tworzenia witryn WWW z wykorzystaniem baz danych: stylem kodu oraz unikaniem częstych pułapek.
388____________________________________Część II » PHP i bazy danych
Rozdział 23.
Styl i efektywność rozwiązań na podstawie PHP i bazy danych W tym rozdziale: * Efektywne używanie zasobów bazy danych 4 Przenoszenie pracy na serwer bazy danych 4 Używanie pól daty i czasu w zapytaniach Ten niewielki rozdział jest przeznaczony dla osób, tworzących witryny WWW korzystające z bazy danych, które uważają, że robią coś nieodpowiednio lub nieefektywnie. Być może nie masz doświadczenia z bazami danych, albo twoje strony ładują się zbyt długo. Podamy tu kilka sztuczek i sposobów pozwalających przyspieszyć działanie witryny oraz pokażemy, w jaki sposób system bazy danych może wyeliminować pisanie niepotrzebne-
go kodu w PHP. Jak zwykle, niektóre z naszych przykładów używaj ą funkcji MySQL, ale porady zamieszczone tutaj są ogólne i niezależne od implementacji bazy danych. W tym rozdziale nie pomożemy uruchomić źle działających połączeń z bazą danych. Przewodnik po częstych błędach, pułapkach i problemach z bazą danych zamieszczony jest w rozdziale 24.
390_______________________________________Część
II
»
PHP
i
bazy
danych
Połączenia — ograniczanie i powtórne użycie Ważne, abyś pamiętał, że nawiązanie połączenia z bazą danych jest zawsze kosztowną operacją. Jeżeli twój skrypt nie wykonuje intensywnych obliczeń, to interakcja z bazą danych będzie najbardziej czasochłonną częścią kodu, pochłaniającą też najwięcej zasobów. Najczęściej sprawdza się twierdzenie, że nawiązanie połączenia jest najbardziej kosztowną częścią kodu, nawet gdy połączenie jest nawiązywane na stronie tylko raz. Istnieją tutaj dwa potencjalnie konkurencyjne cele. Z jednej strony zminimalizowanie
liczby kosztownych i czasochłonnych wywołań funkcji do otwarcia zupełnie nowego
połączenia z bazą danych. W przypadku tego podejścia optujemy za pozostawieniem otwartego połączenia zamiast zamykania go i powtórnego otwierania. Z drugiej strony, istnieją czasami ograniczenia liczby jednocześnie otwartych połączeń, jakie może obsłużyć serwer bazy danych. W takim przypadku stawiamy na zamykanie połączeń tak szybko, jak jest to możliwe, w nadziei, że krótszy czas połączenia pozwoli na jednoczesne wykonanie większej liczby skryptów. Według naszych obserwacji, większość skryptów WWW nie wymaga nakładu na zamykanie i powtórne otwieranie połączenia z bazą danych w trakcie wykonywania jednego skryptu. Jeżeli chcesz zminimalizować czas połączenia z bazą danych, otwieraj połączenie bezpośrednio przed pierwszą operacją na bazie danych i zamykaj natychmiast po wykonaniu ostatniej.
Przykład nieprawidłowego użycia: jedno połączenie na wyrażenie Nasz pierwszy przykład nieprawidłowego użycia wydaje się stylistycznie uzasadniony,
ponieważ przy użyciu tej funkcji można eliminować powtarzający się kod.
$my_connection = mysql_connect('localhost', $user, $pass); mysql_select_db { $db, $my_connection }; $result_id = mysql_query( $query, $my_connection); print("
Wynik zapytania: $query
"); print("
"); while ($tow = mysql_fetch_row($result_id)) f print("
Rozdział 23. » Styl i efektywność rozwiązań na podstawie PHP i bazy danych__________391
)
/* kod używający funkcji box__query{) */ ?>
Funkcja ta pobiera określone zapytanie MySQL i wyświetla jego wynik w atrakcyjnej tabeli HTML. Podstawową zaletą takiej definicji funkcji jest jej niezależność — otwiera połączenie z bazą danych tylko dla własnych potrzeb i po zakończeniu pracy zamyka je. Powyższy kod sprawdza się świetnie, jeżeli spodziewamy się wyświetlenia tylko jednej tabelki na stronie. Jeżeli jednak użyjemy tej funkcji więcej niż raz na stronie, będzie otwierała i zamykała połączenie z bazą danych za każdym jej wywołaniem, co jest mniej efektywne niż pozostawienie otwartego połączenia. Jak wcześniej wspomnieliśmy, naczelną zasadą jest pozostawianie otwartego połączenia, dopóki jest ono potrzebne na bieżącej stronie. Zastosowanie tej zasady do przedstawionej funkcji powinno spowodować jej zmodyfikowanie i pobieranie połączenia jako argumentu (lub niejawne
używanie otwartego połączenia na początku skryptu), a następnie otwarcie jednego połączenia na stronę.
Kilka wyników nie wymaga kilku połączeń Co nas w wielu bazach danych zaskoczyło, gdy zobaczyliśmy pierwszy skrypt korzystający z bazy, to możliwe utrzymywanie wyniku więcej niż jednego zapytania jednocześnie nawet wtedy, gdy istnieje otwarte tylko jedno połączenie. Na przykład przy użyciu bazy danych MySQL można wykonać coś takiego: mysql_connect('localhost', $user, $pass); // otwarcie połączenia mysql_select_db('sienceguide') ;
$author_result = mysq_query("select ID from author")
or die(mysql_error()); while ($author_row = mysql_fetch_row{$author_result)) (
}
$book_result = mysql_query("select title from book where authorlD = $author_row[0]"}; while ($book_row = mysql_fetch_row($book_result)) { Stitle = $book_row[0]; print("Stitle "); )
Fragment ten powinien wypisać tytuły książek, odczytanych z tabeli książek, przy użyciu identyfikatorów, odczytanych z tabeli autorów. Przykład ten pokazuje co prawda skrajnie nieefektywną metodę pobierania danych (spójrz do części „Przenoszenie pracy na serwer bazy danych"), ale ilustruje fakt, że dwa różne zestawy wyników (identyfikowane przez zmienne $author_result i $book_result) mogą być używane w tym samym czasie, po ich odczytaniu poprzez to samo połączenie.
Trwałe połączenia Jeżeli przekonałeś się, że nakłady na otwieranie nowych połączeń do bazy danych zabijają wydajność, możesz zapoznać się z otwieraniem trwałych połączeń. W przeciwieństwie do zwykłych połączeń z bazą danych połączenia takie nie są automatycznie
392____________________________________Część II » PHP i bazy danych
niszczone podczas zakończenia wykonywania skryptu (lub nawet za pomocą wywołania funkcji myql_close ( ) ) , ale są przechowywane w puli połączeń do późniejszego użycia. Za pierwszym razem, gdy jeden ze skryptów otwiera połączenie, jest ono otwierane w taki sam pochłaniający zasoby sposób jak zwykłe połączenie. Jednak następny wykonywany skrypt w odpowiedzi na żądanie może dostać to samo połączenie (poprzednie
połączenie będzie użyte tylko wtedy, gdy parametry nowego żądania są identyczne z poprzednim).
Funkcja żądania otwarcia trwałego połączenia z MySQL to mysql_pconnect ( ) , która jest używana w dokładnie taki sam sposób jak mysql_connect ( ) . Taka konwencja nazywania funkcji PHP wydaje się być stabilna w przypadku funkcji PHP dla innych baz danych —jeżeli używasz funkcji „connect" określonej bazy danych, powinieneś sprawdzić, czy istnieje odpowiednia funkcja „pconnect". Trwałe połączenia do bazy danych istnieją tylko w przypadku instalacji PHP jako moduł. Jeżeli zażądasz trwałego połączenia w wersji CGI, po prostu dostaniesz zwykłe połączenie. Oprócz zwiększania wydajności trwałe połączenie z bazą danych nie ma żadnych dodatkowych funkcji, w porównaniu do zwykłych połączeń. Nie powinieneś oczekiwać „pamięci" poprzednich zapytań lub wartości zmiennych z wykonania poprzednich skryptów.
Przenoszenie pracy na serwer bazy danych Jak w przypadku pisania kodu w dowolnym języku programowania, pisanie kodu współdziałającego z bazą danych jest ćwiczeniem odpowiedniego podziału pracy. Ludzie piszący języki programowania i bazy danych zgodzili się na automatyzację, standaryzację
i optymalizację niektórych zadań często wykonywanych w czasie programowania, więc programiści nie muszą ciągle „wynajdywać na nowo koła" w czasie tworzenia kolejnych aplikacji. Ogólna zasada brzmi: o ile nie chcesz poświęcać wiele energii na optymalizację kodu dla specjalnego zastosowania, lepiej użyj mechanizmu bazy danych, zamiast wymyślać własne rozwiązanie tego samego zadania.
Baza jest szybsza od ciebie Programy baz danych są często oceniane na podstawie ich szybkości, więc programiści
baz danych poświęcają dużą część czasu na usprawnienie szybkości wykonywania zapytań. Każde szukanie wartości lub sortowanie zawartości bazy danych powinno być realizowane przez bazę (o ile jest to możliwe), a nie przez twój kod.
Rozdział 23. » Styl i efektywność rozwiązań na podstawie PHP i bazy danych_________393
Przykład nieprawidłowego użycia: pętla zamiast warunku Dla przykładu zamieszczamy następujący fragment kodu (proszę się nie śmiać — widzieliśmy już takie kwiatki): function print_first_name_bad( Slastname, Sdbconnection } { $query = "select firstname, lastname from author"; $result_id = mysql_query(Squery, Sdbconnection ); while ($row = mysql_fetch_array($result_id)) ( if ($row('lastname'] == Slastname) print("Imie to ". $row['firstname']); }
)
Gdy przekażemy do tej funkcji nazwisko i połączenie do bazy danych, wypisze ona związane z nazwiskami imiona z tabeli „author", o ile takie istnieją. Dla przykładu wywołanie print_first_name_bad( 'Sagan' ,
$dbconnection) może dać nastę-
pujący wynik Imię to Carl
Jeżeli istnieje wielu autorów o takim samym nazwisku, zostanie wypisanych wiele wierszy.
Problemem jest to, że nie potrzebujemy pobierać wszystkich danych z tabeli, „przepychać przez cienką rurę", odczytywać i wybierać odpowiednie rekordy po naszej stronie połączenia. W zamian powinniśmy użyć w zapytaniu warunku za pomocą klauzuli
WHERE:
function print_first_name_beter( Slastname, $dbconnection ) { $query = "select firstname, lastname from author where lastname = $łastname"; $result_id = mysql_query($query, Sdbconnection );
while ($row = mysql_fetch_array($result_id)) ( print("Imie to ". Srow['firstname']);
)
}
Klauzula WHERE zapewnia, że otrzymamy tylko interesujące nas wiersze. Nie tylko pozwala na ograniczenie ilości danych przesyłanych przez połączenie SQL, ale kod użyty do odszukania właściwych wierszy w bazie danych będzie oczywiście szybszy niż twój kod PHP.
Sortowanie i agregacja Dokładnie tego samego argumentu powinieneś użyć, gdy będziesz chciał sam napisać fragment sortujący wyniki zwrócone przez bazę danych, zliczający, liczący średnią (al-
bo w inny sposób agregujący wyniki). Klauzula ORDER BY w SQL pozwala na posortowanie pobranych wierszy według dowolnej listy kolumn w zapytaniu; sortowanie to będzie prawdopodobnie efektywniejsze niż jakikolwiek własny kod lub funkcja PHP
394______________________________________Część II » PHP i bazy danych
sortująca tablicę. Podobnie, zamiast przeglądać wiersze bazy danych w celu zliczenia, zsumowania lub obliczenia średniej, sprawdź, czy twoja baza danych pozwala na użycie w SQL konstrukcji GROUP BY oraz funkcji do użycia w zapytaniach: count (), sum () i average ( ) . Zwykle wykonanie zapytania: Squery = "select count(ID) from author";
jest o wydajniejszym sposobem liczenia wierszy tabeli niż pobranie ich i liczenie ich w pętli PHP.
Tworzenie pól daty i czasu Chcesz powiązać datę i czas z wartościami zapisanymi w wierszu tabeli? Wiersze tabeli mogąnp. reprezentować żądania użytkowników do twojego serwera WWW.
W chwili obecnej jedynym sposobem na wstawienie lub zmianę pól daty jest podanie ciągu reprezentującego żądaną datę w formacie czytelnym dla bazy danych. Jeżeli chcesz np. ustawić na określoną datę pole mydate typu datetime wszystkich wierszy tabeli, możesz to zrobić za pomocą takiego pytania: $query = "update mytable set myquery = 'September 4, 2001'";
Następnie wysyłamy takie zapytanie do wykonania (niestety standardy formatów daty różnią się w zależności od systemu baz danych SQL). Poprzednie wyjście jest dobre, dopóki ciąg z datą jest prawidłowy dla twojej bazy danych. Sprawy się komplikują, gdy potrzebujesz takiego ciągu na bieżąco, aby reprezentował datę uzależnioną od wartości zmiennych w skrypcie. Należy jednak pamiętać, że w większości systemów baz danych nie ma potrzeby przechodzenia przez te męki przy ustawianiu pola na bieżącą datę i czas. Zwykle dostępna jest funkcja zwracająca bieżącą datę; używa się jej bezpośrednio w zapytaniu. Poprzednie zapytanie w wersji dla MySQL, które ustawia odpowiednie pole daty i czasu na datę bieżącą, wygląda następująco: Squery = "update mytable set myquery = now()";
Zauważ, że wywołanie funkcji nów ( ) nie jest otoczone apostrofami. Analogiczne zapytanie dla Microsoft SQL Server wygląda następująco: Squery = "update mytable set myquery = getdateU";
Jeżeli data, którą chcesz zapisać, nie jest datą bieżącą, są lepsze sposoby od tworzenia w skrypcie czytelnego dla serwera ciągu z datą. Wiele wersji SQL ma, oprócz funkcji zwracających bieżącą datę, funkcje wykonujące operacje na datach. Możesz dodać lata, miesiące lub godziny do dowolnej daty. W MySQL takąfunkcjąjest: ^ date add(date, date-interval)
Rozdział 23. » Styl i efektywność rozwiązań na podstawie PHP i bazy danych__________395
Parametr date-interval jest ciągiem określającym liczbę jednostek czasu i rodzaj
ich. Zapytanie MySQL ustawiające wszystkie wiersze na datę o tydzień późniejszą od dnia dzisiejszego wygląda następująco: Squery = "update mytable set mydate = date_add(nów(), '7 days1)";
Szukanie ostatnio wstawionego wiersza Inną pomocną funkcją, oferowaną przez niektóre systemy baz danych jest szukanie identyfikatora ostatnio wstawionego wiersza. Problem pojawia się, gdy próbujesz utworzyć nową pozycję w bazie danych, która jest
rozproszona w kilku tabelach (każda z tych tabel ma klucz główny o automatycznie
zwiększającej się wartości). Jako przykład weźmy tabele utworzone za pomocą następujących wyrażeń MySQL: create table author) ID int primary key, auto_increment, lastname varchar(75), firstname varchar(75)); create table book (ID int primary key, auto_increment, authorlD int, title varchar(100));
Jednym założeniem w przypadku tych wyrażeń jest połączenie tabeli book z tabelą author w taki sposób, że b o o k . a u t h o r l D = a u t h o r . I D . Kolejnym założeniem jest automatyczne przypisanie przez bazę danych unikalnych identyfikatorów w tych tabelach. Niestety połączenie tych założeń prowadzi do problemów. W jaki sposób mamy napisać kod, który wstawi połączoną parę książka-autor, jeśli zarówno książka, jak i autor są
nowi w bazie danych? Jeżeli wstawimy nowego autora, pole ID wstawionego wiersza
będzie automatycznie utworzone przez bazę danych, więc nie jest częścią twojego wyrażenia SQL. W jaki sposób mamy podać właściwą wartość pola authorlD w nowym
wierszu tabeli book? Jedną z możliwych strategii pokazujemy w poniższym przykładzie (w MySQL): Sauthor_lastname = 'Feynman'; $author_firstname = 'Richard';
$book_title = 'The Character of Physical Law 1 ;
$author_insert = "insert into author(lastname, firstname) values! '$author_lastname', 'Sauthor_firstname')"; mysql_query($author_insert) or die(mysql_error());
Sauthor_id_query = "select ID from author where lastname = ' Sauthor_lastname' and firstname = '$author_firstname'"; $author_id_result = mysql_query($author_id_query) or die(mysql_error()); if (mysql_num_rows($author_id_result) <= 0) die ("Nie odnaleziony wstawiony autor!"};
else $author_row = mysql_fetch_row($author_id_result); SauthorlD = $author_row[0]; $book_insert = "insert into book (authorlD, title)
values (SauthorlD, $book_title)"; mysql_query($author_insert) or die(mysql_error());
396____________________________________
Część II » PHP i bazy danych
W kodzie tym tworzymy nowy wiersz autora i używając nazwiska oraz imienia wybieramy ten nowo wstawiony wiersz, zapamiętując przypisany identyfikator nowego wiersza. Następnie dodajemy ten identyfikator do wyrażenia wstawiającego nowy wiersz do tabeli book. Kod ten będzie prawdopodobnie działał w niektórych przypadkach, jeżeli założymy, że imię i nazwisko autora są wystarczające do jednoznacznej identyfikacji rekordu. Niestety w wielu bazach danych nie można utworzyć takiego założenia, co jest oczywiście powodem stosowania unikalnych identyfikatorów. Podobnym wyjściem, które jest czasami używane, jest wstawianie wiersza (na przykład to tabeli autorów) i pobieranie wiersza o największym identyfikatorze (teoretycznie jest wstawiony najpóźniej). Jest to niestety rozwiązanie, które działa tylko wtedy, gdy jest testowane przez pojedynczego programistę, a przestaje działać na docelowym serwerze bazy danych, obsługującym wiele połączeń jednocześnie. Problem wystąpi, gdy z inne-
go połączenia przyjdzie żądanie wstawienia rekordu i będzie obsłużone pomiędzy naszym wstawieniem a pobraniem największej wartości identyfikatora. Spowoduje to pobranie nieprawidłowego identyfikatora, przez co nasze drugie wyrażenie wstawienia rekordu będzie miało niewłaściwy identyfikator autora.
Najlepszym rozwiązaniem, o ile jest ono dostępne, jest pozwolenie bazie danych na pilnowanie ostatnio wstawionego identyfikatora i udostępnianie go w bieżącym połączeniu. W ten sposób nie wystąpią problemy synchronizacji, opisane w poprzednim akapicie. PHP oferuje użytkownikom MySQL funkcję mysql_insert_id ( ) , która na podstawie identyfikatora połączenia pobiera identyfikator ostatnio wstawionego wiersza. Możemy użyć tej funkcji do poprawienia poprzedniego przykładowego kodu: Sauthor_lastname = 'Feynman1; Sauthor_firstname = 'Richard1; $book_title = 'The Character of Physical Law';
$author_insert = "insert into author(lastname, firstname) values! '$author_lastname', 'Sauthor_firstname')"; mysql_query(Sauthor_insert) or die(mysql_error()); SauthorlD = mysql_insert_id{) ; $book_insert = "insert into book (authorlD, title) values ($authorID, $book_title)"; mysql_query($author_insert) or die(mysql_error()};
Jak w przypadku wielu funkcji PHP i MySQL, identyfikator połączenia w funkcji mysql_insert_id ( } jest opcjonalny i domyślnie przyjmuje ostatnio otwarte połączenie. W niektórych systemach baz danych identyfikator ostatniej automatycznie zwiększają-
cej się wartości jest dostępny (w sesji) jako „specjalna" zmienna, której można użyć
w kolejnym zapytaniu. W Microsoft SQL Server zmienną tą jest '%%identity'; w celu odczytania identyfikatora ostatnio wstawionego rekordu można wstawić ją do zapytania w następujący sposób: $query = "select %%identity";
Rozdział 23. » Styl i efektywność rozwiązań na podstawie PHP i bazy danych_________397
Podsumowanie Ponieważ funkcje związane z bazą danych są pochłaniają najwięcej zasobów, możesz korzystać z bardziej efektywnych technik kodowania. Jeżeli twoje skrypty sterowane danymi są ociężałe, powinieneś nauczyć się działać razem z bazą danych, zamiast przeciwko niej. Podstawowe zasady stosowane w kodzie intensywnie korzystającym z bazy są proste. Dużo kosztuje otwarcie połączenia z bazą, więc nie zamykajmy go niepotrzebnie. Pamiętaj, że powinieneś przenosić jedynie minimum danych potrzebnych na stronie. Poświęć nieco czasu na nauczenie się funkcji oferowanych przez twoją bazę danych. SQL jest naprawdę dobry do sortowania, filtrowania, ograniczania, zliczania i grupowania — możesz go użyć, zamiast posługiwać się wolniejszym PHP. W następnym rozdziale odejdziemy od wskazówek i kwestii stylistycznych. Zajmiemy się problemami i pułapkami, które mogą popsuć kod korzystający z bazy danych lub spowodować niespodziewane wyniki.
.39§_________________.____________________Część II » PHP i bazy danych
Rozdział 24.
Pułapki tandemu PHP-baza danych W tym rozdziale: * Brak połączenia * Problemy z uprawnieniami
* Nieoznaczone apostrofy * Nieprawidłowe zapytania SQL * Zbyt mało lub zbyt dużo danych W tym rozdziale opisujemy kilka często występujących problemów z połączeniem PHP z bazą danych. Celem tego rozdziału jest pomoc w diagnozowaniu przyczyn problemu oraz ich szybsze rozwiązywanie. Jak zwykle, nasze przykłady kodu oraz odwołania do funkcji mają za podstawę bazę danych MySQL, ale przedstawiony zbiór pułapek jest całkowicie niezależny od rodzaju bazy danych. W tym rozdziale zajmujemy się diagnozowaniem i poprawianiem kodu PHP, który jest nieprawidłowy — to znaczy, że nie potrafi odczytać danych lub powoduje generowanie błędów. Jeżeli twoje skrypty działają, ale powoli, wróć do poprzedniego rozdziału.
Brak połączenia Jeżeli w skrypcie PHP masz odwołanie do bazy danych, a otwarcie połączenia nie udało się, zobaczysz jeden z dwóch przedstawionych poniżej ostrzeżeń (w zależności od ustawionego poziomu ostrzeżeń, a także, w pewnym stopniu, od tego, co spowodowało problem).
400______________________________________Część II » PHP i bazy danych
Pierwszy z możliwych ekranów ostrzeżenia o braku połączenia pokazany jest na rysunku 24.1. Rysunek 24.1.
Ostrzeżenie o braku połączenia
Wskazuje to na problem z serwerem MySQL lub z ścieżką do mysqld. W ten specyficzny sposób PHP próbuje nam powiedzieć, że wie on o MySQL, ale nie potrafi się z nim połączyć. Pierwsza wprowadzona na rynek wersja PHP 4, 4.0.0 posiadała nieprawidłową funkcję mysqi_connect o , która nie działała, gdy otrzymała jakikolwiek argument. Wersja funkcji dla połączenia trwałego (mysqi_ pconnecto) działała bez problemów. Błąd ten został poprawiony w PHP 4.0.1. Jeśli posiadasz wersję 4.0.0, a chcesz skorzystać z mysqi_connect o , powinieneś zainstalować nowszą wersję.
Jeżeli problem leży po stronie PHP, ekran błędu będzie raczej wyglądał jak ten pokazany na rysunku 24.2. Rysunek 24.2.
Z tych dwóch przypadków błąd krytyczny jest prostszy do poprawienia. Jeżeli otrzymasz błąd wywołania niezdefiniowanej funkcji, która występuje w zestawie funkcji PHP, na pewno zapomniałeś dodać tego modułu podczas instalowania PHP. W przypadku systemu Unix powinieneś skompilować ponownie PHP z opcją -with-mysql. W przypadku Windows wszystkie dostępne opcje są już skompilowane w dostarczonym programie,
więc powinna być dostępna odpowiednia instalacja, albo możesz włączać i wyłączać poszczególne funkcje w p\\kuphp.ini. W przypadku MySQL (lub innej obsługiwanej bazy danych) wystarczy po prostu odkomentować wiersz zawierający php_mysql.dll w pliku php.ini i PHP jest już gotowy do pracy (chyba że umieściłeś pliki programu MySQL w bardzo dziwnym miejscu, chociaż nie powinieneś tego robić). Niewinnie wyglądający błąd braku połączenia jest nieco trudniejszy do zdiagnozowania, ponieważ może wystąpić kilka różnych przyczyn błędu. Można je przypisać do jednej z dwóch kategorii:
1. Demon MySQL nie działa. 2. MySQL używa innego gniazda, niż się spodziewa PHP.
Łatwo sprawdzić, czy program mysqld pracuje, więc możemy to zrobić na początku. Można tutaj użyć dowolnej metody, jakiej zwykle używasz do sprawdzania pracujących procesów. Na Windows NT oznacza to, że trzeba użyć kombinacji Ctrl+Alt+Delete, aby wywołać Task Managera. W systemach Unix, gdzie swoboda wyboru jest ogromna, możesz sprawdzić procesy systemu poprzez wywołanie p s lub graficznego programu monitorowania systemu, albo nawet uruchamiając mysqladmin.
Jeżeli mysqld nie działa, prawdopodobnie po prostu zapomniałeś go uruchomić (proszę się nie śmiać, to się zdarza). Jeżeli działał on bez przerwy 143 dni przed niespodziewanym zakończeniem pracy w środku operacji, problem twój wykracza poza ramy tej książki. Możemy jedynie skierować cię do witryny MySQL i mieć nadzieję, że serwer był regularnie składowany. Problemy z gniazdami zwykle występują za pierwszym razem po uruchomieniu MySQL na nowym serwerze. Jest to raczej rzadko występujący problem w przypadku działającego już serwera, jednak czasami się zdarza. Ostatnio mieliśmy przypadek w jednej z witryn, gdy demon MySQL został przeniesiony na inny serwer bez uprzedniego powiadomienia, co spowodowało, że wszystkie skrypty używające jako nazwy komputera localhost natychmiast przestały działać. Rozwiązanie problemów z podłączeniem do bazy danych znajduje się zwykle w pliku php.ini. Istnieją tam sekcje zmiennych MySQL, w których należy dokładnie sprawdzić, czy podane tam: nazwa komputera, port i gniazdo zgadzają się z tym, co podajesz w skryptach PHP. Powinieneś się upewnić, że przypadkowo nie wskazujesz, aby PHP szukał MySQL poprzez dziwny port lub na niewłaściwym komputerze. W systemie Unix możesz również sprawdzić w pliku /etc/services, czy nie ma tam innych adresów gniazd. Jeżeli nie masz innych poważnych powodów, powinieneś pozostawić te zmienne puste.
402____________________________________Część II » PHP i bazy danych
Problemy z uprawnieniami Komunikaty o błędach, powodowane przez problemy z uprawnieniami, wyglądają podobnie do opisanych przed chwilą problemów z nawiązaniem połączenia. Rysunek 24.3.
Problemy z uprawnieniami
Kluczową różnicą jest mały fragment o nazwie użytkownika i haśle. Ponieważ komunikaty naruszają nieco system bezpieczeństwa, najlepiej na docelowej witrynie używać trybu „cichego". Można to zrobić przez dodanie znaku '@' przed funkcjami mysqi_connect oraz mysql_select_db.
Istnieje wiele takich komunikatów, ale można je przypisać do jednej z poniższych kategorii: * Błędnie wpisana nazwa użytkownika lub hasło. * Nieudane użycie hasła. * Próba użycia nieistniejącego hasła. * Próba użycia użytkownika i hasła systemowego zamiast użytkownika i hasła MySQL. * Użycie użytkownika bazy danych, który ma niewystarczające uprawnienia do wykonania operacji. + Próba logowania z lokacji lub klienta; MySQL nie pozwala na pracę określonych użytkowników. * PHP nie może otworzyć pliku haseł bazy danych z powodu nieodpowiednich uprawnień pliku (musi być to plik do odczytu w katalogu dostępnym dla wszystkich). * Administrator bazy danych zabrał ci uprawnienia do korzystania z bazy danych.
Nie są to problemy strukturalne, ale zwykle skutki zapomnienia ważnych dla pracy systemu parametrów. Błędy te można łatwo naprawić w większości sytuacji.
Nieoznaczone apostrofy Apostrofy mogą powodować wiele małych, choć dokuczliwych problemów pomiędzy PHP i MySQL. Sednem problemów jest fakt, że PHP przetwarza ciągi w cudzysłowach i ignoruje apostrofy, natomiast MySQL przetwarza ciągi w apostrofach i ignoruje cudzysłowy. Prowadzi to do sytuacji, w których musisz dokładnie określić przeznaczenie każdego z tych znaków. Przykładem takiego wyrażenia jest: mysql_query("INSERT INTO book (ID, title, year, ISBN)
VALUES ('NULL 1 , '$title', 'Syear1, '$ISBN')");
W PHP zmienne w apostrofach nie są rozwijane, natomiast zmienne w cudzysłowach są — więc to wyrażenie wygląda nieco dziwnie. Jeżeli jednak chwilę nad nim pomyślisz,
stwierdzisz, wyrażenie jest prawidłowe w obu językach. Apostrofy występują w cudzysłowach, więc PHP traktuje je dosłownie; zmienne znajdują się w cudzysłowach, więc
PHP podstawia na ich miejsce wartości tych zmiennych. Można o tym myśleć jako
o podziale pracy: w zapytaniu do bazy danych PHP wykonuje pracę w ciągach ograniczonych cudzysłowami (traktując apostrofy dosłownie), natomiast MySQL przetwarza następnie te wyrażenia z napisami w apostrofach. Niestety musisz być bardzo ostrożny podczas pisania takich wyrażeń. Jest to jeden z po-
wodów, dla których zaleca się podział kwerend MySQL na dwie części, jak na przykład: Squery = "INSERT INTO book (ID, title, year, ISBN)
Styl taki eliminuje również podwójne nawiasy, które również są częstą przyczyną błędów w kodzie PHP. Jeszcze większe problemy pojawiają się, jeżeli pracujemy z ciągami, które zawierają w tekście apostrofy lub cudzysłowy. Pamiętaj, że apostrofy i cudzysłowy są tym samym dla PHP i MySQL — nie ma żadnej sprytnej opcji, która rozwiązuje te problemy. Zapytania wstawiające dane nie będą wykonywane, jeżeli jakiekolwiek nazwisko będzie posiadało w sobie apostrof (np.: O'Hara): $query = "INSERT INTO employee (ID, lastname, firstname)
VALUES ('NULL', 'Slastname', 'Sfirstname')";
Sresult = mysql_query($query) ;
Inną, równie częstą przyczyną tych problemów są nazwy firm z apostrofami w nazwie, takie jak Rosalita's Bar oraz jakiekolwiek angielskie napisy zawierające skrótowce lub zaimki dzierżawcze (jak na przykład can't, what's lub Mike's)'.
' Ponieważ w języku polskim nie występują tego typu konstrukcje, można być nieco spokojniejszym, ale już witryna zawierająca recenzje filmowe nie jest bezpieczna.
404_______________________________________Część
II
»
PHP
i
bazy
danych
Podobnym zagadnieniem po stronie PHP są ciągi zawierające w sobie cudzysłowy. Na przykład taka konstrukcja na pewno nie zadziała, jak było zakładane: Sstring = "Spiker powiedział: "Pani 0'Hara jest proszona na salę"."; $wyr = mysql_query("INSERT INTO diary (ID, entry) VALUES ('NULL', '$string')");
W przypadku bardzo długich ciągów problemy z cudzysłowami mogą spowodować wstawienie tylko części ciągu lub akceptować tylko krótkie ciągi.
Zajmiemy się teraz trzema sposobami obsługi ciągów z apostrofami i cudzysłowami: 1. Gdy ciąg jest umieszczony bezpośrednio w kodzie, możesz poprzedzić odpowiednie znaki backslashem. Squery = "INSERT INTO employee (ID, lastname, firstname) VALUES ('NULL', '0\'Donnell', 'Sean')";
$result = mysql_query(Squery);
2. Gdy ciąg jest reprezentowany przez zmienną, możesz użyć funkcji addslashes ( ) , która automatycznie doda niezbędne znaki. $string addslashes("Spiker powiedział: 'Pani O'Hara jest proszona na salę'."); $wyr = mysql_query("INSERT INTO diary (ID, entry)
VALUES ('NULL', 'Sstring')");
3. Możesz skompilować PHP z opcją -with-magic-quotes lub ustawić ma-
gic-quotes w plikuphp.ini. Spowoduje to automatyczne dodawanie znaków backslash bez potrzeby wykonywania funkcji addslashes ( ) . Jeżeli twój dostawca Internetu nie pozwala ci zmieniać zawartości pliku php.ini, możesz ustawić tą zmienną przy użyciu swojego pliku .htaccess.
Z niezrozumiałych dla nas przyczyn wielu użytkowników PHP nie lubi używać za każdym razem funkcji addslashes () i jej partnera, funkcji stripslashes (). Raczej wikłają się w wymienianie cudzysłowów na apostrofy, gdy naprawdę nie muszą tego robić, jeżeli oznaczą backslashami wszystkie cudzysłowy. To praktyka w złym stylu, a jest szczególnie niebezpieczna, gdy korzysta się z bazy danych. Musisz dodać znaki backslash, gdy umieszczasz dane w bazie danych, a usunąć je po odczytaniu ciągu z bazy danych (chyba że masz włączoną opcję magic-quotes). Squery = "SELECT passphrase FROM userinfo WHERE username='Susername'"; Sresult = mysql_query(Squery) ; $query_row = mysql_fetch_array(Sresult ); Spassphrase = stripslashes(Squery_row[0]);
Jeżeli tego nie zrobisz, za każdym wstawieniem danych do MySQL będzie dodawane coraz więcej znaków backslash! Jest to dosyć częste w przypadku formularzy na stronach WWW, które wyświetlaj ą dane pobrane z bazy danych, jak pokazano na rysunku 24.4.
J
Rozdział 24. » Pułapki tandemu PHP-baza danych
405
Rysunek 24.4.
Nieusunięte z danych znaki backslash
Nieprawidłowe zapytania SQL Oprócz problemów z apostrofami istnieje wiele możliwości wysłania „nieprawidłowego" zapytania do bazy danych. Zapytanie takie może być nieprawidłowe składniowo lub odwoływać się do nieistniejącej tabeli, mimo że jest składniowo poprawne. Typowy komunikat pokazany jest na rysunku 24.5. Rysunek 24.5.
Błąd powodowany przez nieprawidłowe zapytanie SQL
Nieprawidłowe zapytanie SQL nie jest tym samym, co zapytanie niezwracające żadnych wierszy. Można napisać idealnie prawidłowe zapytanie SQL, jak na przykład: "select ID from cust where name ='nieistniejący'"
406______________________________________Część II * PHP i bazy danych
Jeżeli wyślesz je do bazy danych, w odpowiedzi dostaniesz całkowicie prawidłowy wynik, który zawiera dokładnie O wierszy. Oznacza to, że procedury obsługi błędów nie pomogą wykryć przypadku, gdy wynik nie zwraca żadnych wierszy. Istnieje funkcja mysqi_num_rows o , która wykonana na identyfikatorze wyniku zwraca liczbę wierszy.
To, w jaki sposób będzie wyglądał ten błąd w przeglądarce, zależy od wersji PHP, wersji bazy danych, ustawień obsługi błędów oraz sposobu obsługi błędów w skrypcie. Kluczem do sukcesu jest wczesne wykrycie awarii. Najlepszym sposobem wykonywania zapytań MySQL jest: $result_id = mysql_query(Squery) or die(mysql_error());
Ponieważ mysqi_query () zwraca wartość FALSE w przypadku niepowodzenia, część die () będzie wykonana tylko w przypadku wystąpienia błędu. Niski priorytet operatora 'or' zapewnia, że die o nie będzie miało żadnego znaczenia w przypisaniu —jeżeli funkcja się powiedzie, to wyrażenie zachowuje się tak, jakby część die () nie istniała. Niepowodzenie powoduje zakończenie skryptu natychmiast po wypisaniu komunikatu o błędzie, zawierającego wszystkie dane, jakie mogli dostarczyć projektanci MySQL. Jeżeli w twojej bazie danych nie ma funkcji informującej o błędzie, możesz uprościć to wywołanie do die($query). Zwykle problem stanie się oczywisty, gdy zobaczysz wysłane właśnie zapytanie. Jeżeli nie umieściłeś procedur obsługi błędów przy wywołaniach zapytań, dostaniesz
pierwsze złe wiadomości, gdy spróbujesz użyć identyfikatora wyniku zapytania w kolejnych odwołaniach do bazy danych. Typowym schematem jest: $my_result = mysql_query{$baa_query);
// ... instrukcje przetwarzania i wyświetlania $row = mysql_fetch_row($my_result); // tu ujawnia się błędy
Typowym komunikatem w MySQL jest „O is not a mysql result identifier in ..." (O nie jest prawidłowym identyfikatorem wyniku mysql). Dzieje się tak dlatego, że zamiast wykryć wartość O zwracaną przez mysql_query ( ) w przypadku błędu, próbujesz użyć
tej wartości jako prawidłowego identyfikatora wyniku.
Mimo że nieprawidłowe zapytania są najczęstszą przyczyną powstawania błędu „O nie jest prawidłowym identyfikatorem wyniku", nie jest to jedyna możliwość. Możesz otrzymać ten komunikat, gdy nieprawidłowo podasz nazwę zmiennej identyfikatora wyniku (dlatego nie jest zainicjowana) lub jeżeli zapytanie nie zostanie w ogóle wykonane (co daje ten sam wynik), l tym razem dużo łatwiej jest wykryć te problemy, jeżeli przechwycisz błąd możliwie najwcześniej.
Pomyłki w nazwach Niestety, oprócz skomplikowanych błędów, tkwiących głęboko w środku programu, istnieje mnóstwo banalnych pomyłek, które jednak bardzo łatwo usunąć. Rozpocznijmy od najczęstszego błędu: podania nieprawidłowej nazwy tabeli, kolumny lub nazwy zmiennej. Nie pomoże analiza wielkości liter w PHP ani MySQL. Jeżeli użyjesz 'mytable' zamiast 'MyTable', możesz spodziewać się błędu. Żadna siła nie zabezpieczy cię przed przypadkowym popełnieniem takiego błędu i jedynie jasne komunikaty mogą pomóc. Co możemy dodać? Pamiętaj, że zdarza się to nawet doświadczonym programistom.
Pomyłki przy przecinkach Pamiętaj, aby w wyrażeniach SQL zawsze umieszczać przecinki poza apostrofami. Coś takiego nie będzie działać: Squery = "UPDATE book SET title='Stitle,' subtitile='Ssubtitle,' isbn='$isbn'
Natomiast takie wyrażenie zadziała świetnie: Squery = "UPDATE book SET title='Stitle', subtitile-'$subtitle', isbn='$isbn'";
Ciągi nieotoczone apostrofami Każdą wartość, która powinna być traktowana przez bazę danych jako ciąg, trzeba otoczyć apostrofami w wyrażeniu SQL. Na przykład zapytanie to ma właściwą składnię: $query =• "select * from author where firstname = 'Daniel'";
Dla odróżnienia, jeżeli wykonamy funkcję mysql_query ( ) z użyciem poniższego ciągu, możemy spodziewać się błędu: Squery = "select * from author where firstname = Daniel";
Komunikat o błędzie zwracany przez bazę danych może być mylący — komunikat ten mówi o nieznanej kolumnie 'Daniel'. Dzieje się tak, ponieważ ciągi nieotoczone apostrofami traktowane sąjako nazwy kolumn, jak w przykładzie: $query - "select * from author where firstname = lastname";
Zapytanie takie może być użyte do wyszukiwania takich autorów, jak na przykład „Lisa Lisa".
Niezainicjowane zmienne Jednym ze sposobów zepsucia zapytania jest umieszczenie w nim niezainicjowanej zmiennej.
408_______________________________________Część II » PHP i bazy danych
System automatycznego wklejania wartości zmiennych do ciągów w cudzysłowach ideal-
nie pasuje do opartego na SQL dialogu z bazą danych, o ile działa poprawnie. W twoim kodzie można określać wartości, które na przykład mogą być użyte do ograniczania liczby
wierszy pobieranych z bazy danych, w sposób pokazany poniżej:
$customerID = find_customer_id(); // funkcja przykładowa, zwraca int $result_id = // BŁĄD mysql_query("select from customers where ID = 3customer_ID"); $row = mysql_fetch_row($result_id); // AWARIA
Ponieważ kod ten nie próbuje przechwycić błędu, znowu zobaczysz komunikat o tym,
że O nie jest prawidłowym identyfikatorem wyniku. Problem leży oczywiście w tym, że wprawdzie przypisaliśmy wartość do zmiennej ($customerlD), ale użyliśmy w zapy-
taniu zupełnie innej ($customer__iD). Zmienna ta jest niezainicjowana, więc w czasie interpretowania ciągu zachowuje się jak pusty ciąg. W wyniku tego baza danych otrzy-
ma następujące zapytanie, które oczywiście jest nieprawidłowe: select from customers where ID =;
Ta kategoria problemów jest kolejnym powodem, dla których warto przypisywać do zmiennych stworzone zapytania, jak na przykład:
$my_query = "select from customers where ID - $customer_ID";
Po takim przypisaniu wykonujemy osobne wywołanie mysql_query($my_query).
Jeżeli pracujesz w ten sposób, bardzo łatwo możesz uruchomić drukowanie lub dodać instrukcje debuggera w celu wyświetlenia aktualnej postaci zapytania, wysyłanego do bazy danych.
Zbyt mało danych, zbyt dużo danych Na koniec zajmiemy się sytuacją, gdy twój skrypt PHP działa pozornie bezbłędnie, ale
nie wyświetla danych lub wyświetla o wiele więcej, niż powinien. Jako zasadę powi-
nieneś przyjąć, że jeżeli funkcja wykonująca zapytanie nie zwraca żadnych błędów
(a odpowiedni kod to sprawdza), podejrzenie powinno paść na samo wyrażenie SQL. Sprawdź ponownie logikę, szczególnie klauzulę WHERE. Łatwo można na przykład napisać takie zapytanie: "select * from families where kidcount = 1 and kidcount = 2";
W tym zapytaniu tak naprawdę chciałeś użyć operatora 'or' a nie 'and', a błąd ten spowodował, że zapytanie nie zwróci nigdy żadnych wierszy, niezależnie od zawartości bazy danych. Jeżeli skrypt przegląda w pętli wiersze tabeli i wyświetla ich o wiele zbyt dużo, problem często leży w tym, że zapytanie ma zbyt mało połączeń. Naczelną zasadą jest, że liczba warunków w klauzuli WHERE nie powinna być mniejsza od liczby łączonych tabel minus jeden. Zapytanie poniższe posiada np. trzy tabele, ale ma tylko jeden warunek złączenia. "select book.title, from book, author, country where author.countrylD - country.ID";
Rozdział 24.
»
Pułapki tandemu
PHP-baza danych__________________________409
Zapytanie to zwróci wszystkie możliwe pary książka — autor, niezależnie od tego, czy autor napisał tę książkę, czy nie, co nie jest prawdopodobnie oczekiwanym wynikiem.
Kontrola poprawności Jeżeli kończą ci się pomysły na szukanie błędów związanych z zapytaniami, użyteczne jest porównywanie wyników zapytań osadzonych w PHP z tymi samymi zapytaniami wykonanymi bezpośrednio na bazie danych. Jeżeli masz możliwość bezpośredniego uruchomienia interpretera SQL (na przykład pisząc w wierszu poleceń mysql) oraz przenoszenia danych pomiędzy programami, możesz wypróbować taki sposób: 1. Wstaw wyrażenie uruchomieniowe do skryptu PHP, które drukuje treść zapytania bezpośrednio przed wykonaniem go w bazie danych (na przykład: print ($query) ;).
2. Wstaw treść zapytania z przeglądarki (lub źródła HTML) do twojego interpretera SQL. Jeżeli zapytanie wygląda dobrze, ale powoduje błąd SQL i PHP, musi być w nim jakiś błąd składniowy lub w nazwie; kod PHP w tym przypadku nic nie zawinił (chyba że konstruuje to zapytanie). Podobnie w przypadku zbyt małej lub zbyt dużej liczby wierszy wyniku —jeżeli zachowanie jest identyczne w obu programach, winne jest zapytanie. Jeżeli zaś zapytanie zachowuje się w interpreterze SQL tak, jak się tego spodziewasz, jest prawidłowe, a podejrzenie pada na kod PHP, wysyłający zapytanie i przetwarzający wynik. Powinieneś bardzo uważnie czytać komunikaty o błędach, zwracając szczególnie uwagę na określenia takie, jak „identyfikator połączenia" oraz „identyfikator wyniku". W MySQL pierwsze oznacza identyfikator połączenia z bazą danych, drugie — identyfikator zestawu wierszy zwracanych przez określone zapytanie. Łatwo pomylić je ze sobą (poniższy fragment kodu): $my_connect = mysql_connect('localhost', $myname, $mypass); mysql_select_db('MyDB'); Sresult = mysql_query($my_query, Smy_connect); while (Srow = mysql_fetch_row($my_connect)) { // ŹLE
Kod ten prawdopodobnie wygeneruje błąd zawierający zwrot „nieprawidłowy identyfikator wyniku". Problem tkwi w tym, że użyliśmy identyfikatora połączenia w miejsce identyfikatora wyniku. Wygenerowany komunikat jest uzasadniony, choć nieco niejasny.
Podsumowanie Błędy PHP w połączeniu z bazą danych nie są zwykle zbyt głębokie, ale mogą być niełatwo je odszukać. Ogólnie mówiąc, im wcześniej błąd zostanie wykryty w skrypcie,
410_______________________________________Część II » PHP i bazy danych
tym łatwiejsze będzie jego zlokalizowanie. Każde wyrażenie współpracujące z bazą danych powinno posiadać dołączoną klauzulę or die ( ) , zawierającą niosący możliwie dużo informacji komunikat o błędzie, szczególnie w trakcie uruchamiania. Jak dotąd najczęstszym powodem problemów z połączeniem z bazą danych są nieprawidłowe wartości argumentów przekazywanych do funkcji łączącej z bazą (nazwa komputera, nazwa użytkownika i hasło). Najczęstszym powodem błędów przy wykonaniu zapytań są problemy z apostrofami, niezainicjowane zmienne i proste pomyłki. Jeżeli powtarzają się problemy z zapytaniami, na pozór zupełnie prawidłowymi, musisz wydrukować treść podejrzanego zapytania przed wysłaniem do bazy danych. Jeżeli to możliwe, wykonaj je bezpośrednio na bazie danych. Jeżeli problem się powtórzy, możesz bezpiecznie skupić się na szukaniu błędu w strukturze bazy danych i twoim rozumieniu zapytań SQL.
Cześć 3
Techniki zaawansowane
Rozdział 25.
Sesje
W tym rozdziale: * Do czego służą sesje
* Śledzenie sesji w PHP
+ Przykładowy program korzystający z sesji ** Ustawianie zmiennych wspomagających sesje W innych częściach tej książki spotykałeś się czasami z ostrzeżeniem „nowa funkcja", które zwykle oznaczało możliwość wprowadzoną w PHP 4.0. Niniejszy rozdział powinien być w ten sposób oznaczony, ponieważ w PHP 3.x nie było wbudowanego mechanizmu śledzenia sesji. Jeżeli chcesz korzystać z sesji użytkownika, musisz zainstalować PHP 4, zastosować popularną bibliotekę PHPLIB lub stworzyć własne rozwiązanie.
Czym są sesje? Co mamy na myśli, mówiąc o sesjach? Nieformalnie, sesja w przypadku przeglądania WWW to czas, w którym dana osoba, siedząc przy jednym komputerze, przegląda określoną liczbę stron, następnie kończy ten proces. Jeżeli prowadzisz witrynę WWW, którą przykładowy użytkownik właśnie przegląda, sesja biegnie od czasu załadowania pierwszej strony, aż do ostatniej. Na przykład witryna hotelu na Karaibach może korzystać z sesji na czas przeglądania pięciu stron, ale użytkownik naprawdę rozpoczął sesję w portalu zajmującym się podróżami, a zakończył ją w czasie rezerwacji miejsca w hotelu konkurencji.
Co stanowi problem? Dlaczego więc idea sesji jest na tyle skomplikowana, że zajmujemy się nią dopiero teraz? Jest tak dlatego, że protokół HTTP jest bezstanowy. Powoduje to, że twój serwer WWW ma mniej pamięci długoterminowej niż twój kod. W rezultacie serwer WWW
.. u
414___________________________________Część III
»
Techniki zaawansowane
odpowiada na poszczególne żądania, jakie otrzymuje, i nie ma sposobu na ich połącze-
nie, nawet jeżeli żądania te są zapisywane. Jeżeli siądę przy moim komputerze w Chicago, a ty przy swoim, i oboje załadujemy kolejno pierwszą i drugą stronę z witryny
hotelu na Karaibach, protokół HTTP nie zaoferuje żadnej pomocy przy rozpoznaniu, że
tych dwoje ludzi oglądało dwie kolejne strony. Od strony serwera były to cztery żądania
załadowania stron, z dodatkowymi danymi związanymi z każdym wywołaniem. Nie tylko taka informacja nie identyfikuje cię (za pomocą nazwiska, adresu e-mail, numeru telefonu lub innego identyfikatora), ale również nie oferuje nic, co może zidentyfikować żądania kolejnych stron jako pochodzące od jednej osoby.
Dlaczego się tym zajmujemy? Jeżeli twoja witryna jest przeznaczona tylko do dostarczania rozmaitych stron różnym użytkownikom, to w zasadzie nie musisz wiedzieć, kiedy sesja się rozpoczyna i kiedy kończy. Jednak istnieje wiele sytuacji, gdy chcemy to wiedzieć. * Chcemy dostosowywać się do doświadczenia użytkowników, które zależy od tego, jakie strony (lub ile) już widzieli. * Chcemy wyświetlać reklamy, ale nie chcemy wyświetlać jednej reklamy więcej niż raz w czasie sesji. * Chcemy zbierać informacje o podejmowanych przez użytkownika działaniach (tak jak w grach przygodowych realizuje się pamiętanie punktów lub w witrynach handlu elektronicznego — wózki na zakupy).
* Interesuje nas sposób, w jaki ludzie korzystają z witryny — czy przechodzą do wewnętrznych stron korzystając z zakładek, czy przechodzą całą drogę od strony głównej. Dla wszystkich zastosowań powinniśmy skorelować żądania załadowania stron z kolejnymi częściami sesji; dla niektórych zastosowań wygodnie byłoby zapamiętywać niektóre dane w połączeniu z sesją. Sesje PHP rozwiązują oba te problemy.
Alternatywy sesji Zanim zajmiemy się podejściem PHP do sesji, wymienimy kilka alternatywnych sposobów rozwiązania problemu. Jak się później przekonamy, podejście PHP stanowi kombinację kilku z tych technik.
Adres IP Serwery WWW znają albo nazwę, albo adres IP komputera, z którego przyszło żądanie załadowania strony. W większości konfiguracji PHP są one dostępne w zmiennych, odpowiednio $REMOTE_HOST i $REMOTE_NAME. Wydaje się, że identyfikacja komputera
Rozdział 25.
»
Sesje_________________________________________415
jest jednoznaczna z użytkownikiem, co najmniej w krótkim czasie. Jeżeli w krótkim okresie dostaniesz dwa żądania z tego samego adresu IP, kod może stwierdzić, że zostały one wysłane przez tę samą osobę, która przeszła z jednej strony witryny na drugą. Niestety adres IP twojej przeglądarki nie musi do komputera, z którego korzysta użytkownik. Zarówno AOL, jak również inni dostawcy stosują serwery proxy, które działają jako pośrednicy. Jeżeli przeglądarka zażąda załadowania URL, wysyła on to żądanie do docelowego serwera i zwraca stronę użytkownikowi, taka konfiguracja powoduje, że wielu użytkowników może jednocześnie przeglądać twoją witrynę pozornie z jednego adresu IP. Adresy IP nie są więc wystarczająco jednoznaczne, aby stanowić podstawę
do śledzenia sesji.
Ukryte zmienne Każde wywołanie HTTP jest obsługiwane niezależnie, ale za każdym razem gdy użytkownik przejdzie do innej strony witryny, jest zwykle realizowane przez łącze lub
przetworzenie formularza. Jeżeli pierwsza strona, którą użytkownik odwiedza, może
wygenerować identyfikator tej wizyty, następne przejścia ze strony do strony mogą go przenosić. Poniższy przykładowy fragment kodu można zamieścić na początku strony: if ( UsSet ($my_s_id) ) $my__s_id = generate_s_id () ;
// to jest hipotetyczna f u n k c j a
Ten fragment kodu kontroluje, czy zmienna $my_s_id została wcześniej zainicjowana.
Jeżeli tak, zakładamy, że została przekazana do bieżącej strony i jesteśmy w środku sesji. Jeżeli nie, oznacza to, że jesteśmy na pierwszej stronie nowej sesji i wywołujemy hipotetyczną funkcję, nazwaną generate_s_id ( ) , w celu utworzenia identyfikatora (jest to trudne zadanie). Założyliśmy, że po włączeniu poprzedniego kodu identyfikator sesji i pozostaje nam jedynie przekazać go do wszystkich połączonych stron. Każde łącze z naszej strony powinno zawierać $my_s_idjako argument GET: ">Następny
Każdy formularz powinien zawierać ukryty argument POST:
Ta technika jest prostym sposobem odróżniania sesji (dopóki możesz generować identyfikatory). Jeśli mamy identyfikatory sesji, możemy zastosować wiele sposobów dołączenia danych do każdej sesji. Jednym z nich jest użycie identyfikatora sesji jako klucza tabeli bazy danych. Jednak to wyjście jest kłopotliwe — musisz upewnić się, że każde łącze i obsługa formularza prawidłowo przenoszą opisane informacje. Jeżeli przesyłasz informacje jako argument GET, maszyna śledzenia sesji będzie widoczna w pasku adresu przeglądarki — argument może być zmieniony lub przechwycony przez użytkownika.
416________________________________Część III » Techniki zaawansowane
Cookie Innym sposobem śledzenia sesji jest użycie takiego samego identyfikatora sesji, jak opisaliśmy przed chwilą, ale do jego przekazywania pomiędzy stronami stosuje się cookie.
Cookie jest szczególnego rodzaju plikiem, umieszczonym w komputerze z przeglądarką, który może być zapisywany i odczytywany przez serwery WWW. Zamiast sprawdzać zmienną przekazaną za pomocą metody GET lub POST (i przypisywać nową, jeżeli nie została odnaleziona), skrypt może sprawdzić, czy w komputerze klienta istnieje już poprzednio utworzone cookie i zapisać do niego nowy identyfikator, jeżeli nie został odnaleziony. Metoda ta posiada pewne zalety w porównaniu do ukrytych zmiennych: mechanizm ten działa w sposób niewidoczny (nie pozostawia zwykle w przeglądarce śladów aktywności), a kod, który sprawdza i ustawia cookie, może być scentralizowany (zamiast występować w każdym łączu). Jakie są wady? Niektóre stare przeglądarki w ogóle nie obsługują cookie, a nowe pozwalają użytkownikowi na zablokowanie możliwości tworzenia cookie przez serwery WWW. Mimo że cookie dostarczają dobre rozwiązanie problemu, nie możemy zakładać, że będą zawsze dostępne. Istnieje subtelna różnica pomiędzy mechanizmem sesji realizowanym za pomocą cookie i tym realizowanym za pomocą zmiennych GET i POST. System na podstawie zmiennych utrzymuje identyfikatory tak długo, jak użytkownik pozostaje w twojej witrynie, przechodząc pomiędzy wewnętrznymi stronami. Istnieje jednak wiele sytuacji, kiedy użytkownik przejdzie do innej witryny i za chwilę wróci z powrotem. Podejście na bazie cookie potraktuje powrót z krótkiej wycieczki jako kontynuację tej samej sesji, natomiast mechanizm przekazywania zmiennej potraktuje ją jako nową wizytę. Funkcje ustawiania i korzystania z cookie opisane są w rozdziale 26. „Cookie i HTTP". Zapoznaj się również z uwagami, zawartymi w tym rozdziale, na temat poszanowania prywatności. Nie umieszczaj również w cookie żadnych ważnych informacji, zanim przeczytasz rozdział 31. „Bezpieczeństwo i kryptografia".
Jak działają sesje w PHP Dobrze działające sesje zajmują się dwiema rzeczami: śledzeniem sesji (to znaczy wykrywaniem, kiedy dwa osobne wywołania skryptów są częścią tej samej sesji) oraz zapamiętywaniem danych związanych z sesją. Musimy mieć pierwszą możliwość, żeby w ogóle myśleć o drugiej.
Zanim dodano w PHP 4 obsługę sesji, głównym zamiennikiem sesji był pakiet PHPLIB. Obsługa sesji w PHPLIB jest koncepcyjnie podobna, ale różni się szczegółami. PHPLIB jest dostępny pod adresem http://phplib.netuse.de (w czasie pisania tej książki PHPLIB nie był zgodny z PHP 4, ale to na pewno zostało już poprawione).
Sesje PHP działają na bazie kombinacji metody ukrytych zmiennych i cookie. Dla zalet cookie PHP będzie używał tej metody, jeżeli jest dostępna; w przypadku braku obsługi
cookie skorzysta ze zmiennych. Na szczęście funkcje obsługi sesji działają na bardziej abstrakcyjnym poziomie i same troszczą się o obsługę cookie i inne szczegóły. Jeżeli
twoja wersja PHP 4 została odpowiednio skonfigurowana do obsługi sesji, możesz użyć sesji bez martwienia się o to, jaka metoda została zastosowana. Jeżeli chcesz, aby PHP przezroczyście obsługiwał przekazywanie zmiennych sesji w przypadku niedostępności cookie, musisz skonfigurować PHP Z Użyciem opcji —enable-trans-sid i —enable-track-vars.
Jeżeli PHP nie zrobi tego za ciebie, musisz dodać do argumentów GET lub POST argument session_name=session_id do wszystkich łączy i formularzy. Gdy sesja jest aktywna, PHP dostarcza specjalną stałą SID, która zawiera odpowiednią parę argument i wartość. Tutaj podajemy przykład dodania tej stałej do łącza: ">Następna strona.
Jeśli cookies nie są dostępne, automatyczne przekazywanie identyfikatora (o ile jest aktywne) przenosi identyfikator sesji metodą GET dla łączy oraz metodą POST dla formularzy. Jednak nie przekazuje tej informacji przez formularze GET. W tym przypadku musimy jawnie przekazać identyfikator sesji w ukrytej zmiennej (zostało to zauważone w wersji beta i pewnie będzie poprawione w kolejnych wersjach). Jeżeli PHP śledzi sesje, można również zachować dane przez „rejestrowanie" określo-
nych zmiennych, w celu wskazania, że ich wartości mają być zapamiętane w połączeniu z identyfikatorem sesji.
Uaktywnianie sesji w PHP Pierwszym krokiem skryptu, korzystającego z sesji, jest poinstruowanie PHP, że sesja może już trwać, więc trzeba j ą przechwycić i odczytać wszystkie związane z nią dane. Realizuje się to przez wywołanie bezargumentowej funkcji session_start (). Jeżeli jest ona wywoływana w każdym skrypcie, możesz j ą pominąć i w zamian za to ustawić w php.ini zmienną session.auto_start na l (jest ona zwykle ustawiona na 0). Również każde wywołanie funkcji session_register ( ) spowoduje niejawne wywołanie session s t a r t { ) .
418________________________________Część III » Techniki zaawansowane
Wynik działania session_start ( ) zależy od tego, czy PHP odszukał poprzedni identyfikator sesji, przekazany przez argumenty HTTP lub cookie. Jeżeli został znaleziony, poprzednio związane z nim zmienne sesji zostaną odczytane i zamienione na
zwykłe zmienne dostępne na stronie. Jeżeli np. poprzednia strona w sesji zarejestrowała
zmienną $city i przypisała jej wartość 'Chicago', nasz skrypt może z niej skorzystać, wywołując session_start ( ) : session_start() ;
print! "$city " );
Jeżeli poprzednio nie została zarejestrowana taka zmienna lub zapomnieliśmy wywołać session_start (), zmienna będzie traktowana jak każda niezainicjowana zmienna. Odczytanie zmiennych sesji przez wywołanie session_start o spowoduje nadpisanie wszystkich zainicjowanych zmiennych o takich samych nazwach, jakie istnieją w chwili wywołania funkcji w skrypcie. Oznacza to, że jeżeli zmienne przekazane są za pomocą GET i POST oraz mechanizmem obsługi sesji na bazie cookie, zmienne sesji „wygrają" w tym pojedynku (więcej o kolejności przypisywania zmiennych GET, POST i cookie w następnym rozdziale).
Jeżeli PHP nie znajdzie poprzedniego identyfikatora sesji, wywołanie session_ start () utworzy nową sesję. Podstawowym efektem jest utworzenie nowego identyfikatora, który może być używany do rejestrowania zmiennych.
Rejestrowanie zmiennych w sesji Wywołanie session_start () zajmuje się importowaniem zmiennych z sesji do bieżącego skryptu — teraz wyeksportujemy zmienne, aby były widoczne w kolejnych stronach w tej samej sesji. Jest to realizowane przez funkcję session_register ( ) . Jak się okazuje, importowanie zmiennych jest „hurtowe" (robimy to jednym wywołaniem funkcji), natomiast eksport jest „detaliczny" (musimy rejestrować kolejno wszystkie zmienne). Należy pamiętać, że to, co zostało zaimportowane, nie jest automatycznie eksportowane, choć tak wskazuje logika.
Załóżmy, że poprzednia strona ustawiła zmienną $city na 'Chicago'. Teraz skorzystamy z tej zmiennej i przekażemy j ą (po zmianie wartości) do kolejnych stron: session_start(); print( "$city " );
session_register('city1);
print! "$city " ); $city = 'Dallas';
Wywołanie session_start () ustawia zmienną $city na 'Chicago', więc można
użyć tej zmiennej w instrukcji print. Od tego miejsca $city będzie traktowane jak każda inna zmienna na stronie. Wywołanie session_register ( ) umieszcza jednak w mechanizmie sesji informację o tym, że zmienna $city ma być ponownie wyeks-
portowana do zmiennych sesji. Na kolejnych stronach wartość jej powinna być taka sama, jak po zakończeniu tego skryptu. W naszym kodzie wartość tej zmiennej zmieniła się na 'Dallas', więc następne strony otrzymają taką właśnie wartość zmiennej. Nazwy zmiennych przekazywane do funkcji session_register o nie powinny zawierać poprzedzającego je znaku '$'.
Jeżeli zapomnimy wywołać funkcję session_start O, pierwszy wiersz będzie zawierał puste miejsca tam, gdzie powinna być wartość zmiennej $city. Drugi drukowany wiersz będzie już wyglądał dobrze, ponieważ wywołanie session_register ( ) powoduje niejawne wywołanie session_start ( ) . Jeżeli opuścimy wywołanie session_register ( ) , na tej stronie wszystko będzie w porządku, ale kolejne strony nie otrzymają zmiennej sesji o nazwie $city. Rejestracja zmiennej jest całkowicie niezależna od przypisywania do niej wartości. Możesz przypisać wartość do zmiennej bez jej rejestrowania (dlatego będzie normalną zmienną strony, która nie jest przenoszona do innych stron) lub możesz zarejestrować zmienną bez przypisywania do niej wartości (będzie ona występowała w kolejnych stronach jako nieprzypisana).
Rejestrowane zmienne są super globalne Użytecznym sposobem myślenia o zmiennych sesji jest uważanie ich za deklarowane super globalnie. Zmienne występujące we wnętrzu definicji funkcji posiadają zasięg ograniczony tylko do tej funkcji, chyba że zostaną zadeklarowane jako globalne. Podobnie zwykłe zmienne mają zasięg ograniczony do skryptu, chyba że zarejestrujemy je jako (super globalne) zmienne sesji.
Gdzie są przechowywane dane? Mechanizm sesji bazuje na identyfikatorze sesji i związanych z nim wartości zmiennych. Jak już wiemy, identyfikator sesji jest przechowywany w cookie w komputerze z przeglądarką lub jest wbudowywany w argumenty GET, POST, przekazywane razem z żądaniem pobrania strony. Nie jest nigdzie zapamiętywany — przekazywany jest jako część żądania i zwracany do kodu HTML, do łączy i formularzy, które mogą wygenerować kolejne żądanie. Przeglądarka i serwer przerzucają się tą krytyczną dla nas informacją jak gorącym kartoflem. Jeżeli któraś ze stron zgubi identyfikator, nasza sesja się kończy. Domyślnie zawartość zmiennych sesji jest przechowywana w specjalnych plikach na serwerze, po jednym dla każdej sesji (można przechowywć identyfikator sesji jako cookie w komputerze klienta, ale byłoby grubiaństwem przechowywanie wartości zmiennych sesji na jego dysku). Zapamiętanie danych w ten sposób wymaga kodu sesji, realizującego serializację danych. Termin ten oznacza zamianę danych w liniową sekwencję bajtów, którą można zapisywać na dysku i odczytywać z niego w celu odtworzenia danych.
420________________________________Część III » Techniki zaawansowane
Mimo że w teorii możemy zarejestrować każdą zmienną, zawierającą dowolny typ PHP, jednak w PHP 4 beta ciągle nie było pewnej obsługi serializacji obiektów. Ten rodzaj obsługi może pojawić się w wersji finalnej bądź kolejnych, ale powinieneś sprawdzić kod rejestrujący zmienne obiektowe, aby się upewnić, czy są one prawidłowo odtwarzane.
Możliwe jest takie skonfigurowanie PHP, aby program przechowywał zmienne sesji w bazie danych zamiast w plikach. Więcej informacji znajdziesz w części „Zagadnienia konfiguracji" poniżej.
Funkcje obsługi sesji Tabela 25.1 zawiera wszystkie najbardziej istotne funkcje związane z obsługą sesji, wraz z opisem ich działania. Zauważ, że w niektórych przypadkach działanie funkcji zależy od ustawień konfiguracji, które zostały opisane w dalszej części rozdziału. Tabela 25.1. Zestawienie funkcji do obsługi sesji
Funkcja
Opis
session start ( )
Nie wymaga argumentu. Powoduje, że PHP odczytuje identyfikator sesji przekazany do strony (dzięki cookie lub GET, POST); jeżeli nie może go odszukać, tworzy nowy identyfikator sesji
Jeżeli odnaleziony został stary identyfikator sesji, PHP odtwarza przypisania do wszystkich zarejestrowanych zmiennych i udostępnia te wartości jako zwykłe zmienne globalne session r e g i s t e r ! )
Wymaga ciągu jako argumentu i rejestruje zmienną o nazwie określonej przez ciąg — na przykład session register ( ' username ' ) . Nazwa
zmiennej nie powinna zawierać początkowego znaku '$'. Można również przekazać tablicę ciągów, aby za jednym razem zarejestrować wiele zmiennych Efektem rejestracji jest zapamiętanie przypisań do obiektu (po zakończeniu skryptu zarejestrowane zmienne podlegają serializacji i są
przenoszone w sposób, który zapewnia ich odtworzenie w wywołaniu session s t a r t ( ) )
Jeżeli nie wywołano wcześniej funkcji session start ( ) , session r e g i s t e r ) ) niejawnie ją wywołuje session u n r e g i s t e r ( )
Wymaga ciągu jako argumentu i usuwa z listy zarejestrowanych zmiennych zmienną o nazwie przekazanej jako argument. W wyniku tego zmienna ta nie będzie podlegała serializacji i nie będzie przenoszona pomiędzy stronami (nazwa zmiennej nie powinna zawierać początkowego
Zestawienie funkcji do obsługi sesji (ciąg dalszy)
Funkcja
Opis
session is r e g i s t e r e d ( )
Sprawdza, czy zmienna o podanej nazwie jest zarejestrowana w bieżącej sesji, zwracając TRUE, jeżeli zmienna jest zarejestrowana, FALSE, jeżeli nie jest
session d e s t r o y ! )
Wywołanie tej funkcji usuwa wszystkie zapamiętane dane o sesji (identyfikator sesji nie musi się zmieniać po wywołaniu tej funkcji). Wywołanie tej funkcji nie zmienia wartości żadnych zmiennych w bieżącym skrypcie
session name ( )
Funkcja wywołana bez parametrów zwraca nazwę bieżącej sesji. Jest to zwykle ' P H P S E S S I D 1 Wywołana z jednym argumentem session name ( ) ustawia nazwę bieżącej sesji na podany ciąg. Nazwa tajest używana jako klucz do odszukania identyfikatora sesji w cookie lub argumentach GET, POST. Aby odnalezienie sesji się udało, nazwa sesji musi być identyczna jak nazwa sesji, w trakcie której poddano zmienne serializacji. Zauważ, że nie ma powodu do zmiany nazwy sesji, chyba że chcesz rozróżniać różne typy sesji obsługiwanych jednocześnie przez serwer WWW (na przykład w przypadku wielu witryn korzystających z sesji). Nazwa sesji jest zmieniana na domyślną za każdym uruchomieniem skryptu, więc zmiana nazwy sesji musi zostać wykonana w każdym skrypcie przed wywołaniem innej funkcji obsługi sesji
session module name ( )
Jeżeli nie zostaną podane żadne argumenty, funkcja zwraca nazwę modułu odpowiedzialnego za obsługę danych sesji. Nazwa tajest domyślnie ustawiona na ' f ileś ' , co oznacza, że dane sesji po serializacji są zapisywane do plików w katalogu ustawionym przez funkcję session save path ( ) . Jeżeli podany zostanie ciąg jako argument, nazwa modułu jest zmieniana na ten ciąg (np. ' u s e r ' dla zdefiniowanej przez użytkownika bazy danych sesji; ale nie powinieneś zmieniać tego parametru, jeżeli nie wiesz dokładnie, co robisz)
session save path ( )
Zwraca (lub ustawia w przypadku podania argumentu) ścieżkę do katalogu, w którym zapisywane są wartości zmiennych sesji (zwykle jest to /tmp w systemach Unix). Katalog ten musi mieć odpowiednio ustawione uprawnienia, aby PHP mógł tam zapisywać pliki
session i d ( )
Nie ma argumentów. Zwraca ciąg, który jest kluczem określającym sesję. Jeżeli zostanie przekazany argument, funkcja ta ustawi identyfikator sesji na tę wartość
session encode ( )
Zwraca ciąg z zakodowanym stanem bieżącej sesji, który może zostać zdekodowany przez funkcję session decode ( ) . Ciąg ten może zostać użyty do zapamiętania sesji w celu odtworzenia jej za jakiś czas (np. zapisanie zakodowanego ciągu w pliku lub bazie danych)
session d e c o d e ! )
Pobiera wynik działania funkcji session encoded i odtwarza stan sesji, zmieniając zmienne sesji na zmienne strony (analogicznie do session start ( ) )
422___________________________________Część III
» Techniki zaawansowane
Przykładowy kod sesji Kod zamieszczony na wydruku 25.1 posiada podwójne przeznaczenie: pokazuje niektóre funkcje obsługi sesji w działaniu (szczególnie session_start (), session_regis-
ter ( ) , session_id ( ) oraz session_destroy ( ) ) , można go użyć do testowania własnych implementacji sesji. Skrypt ten zawiera jedną stronę, która ma łącze do samej siebie, oraz formularz przetwarzany przez ten sam skrypt. Wydruk 25.1. Skrypt testujący sesje______________________________________
session_start{); session_register('pagecount'); session_register('username');
Identyfikatorem sesji jest Może istnieć więcej innych identyfikatorów sesji, ale ten jest twój.
Nie zapisuj bieżącego identyfikatora sesji. Jest on tak naprawdę tylko identyfikatorem technicznym. PHP potrzebuje go do działania, ale ty prawdopodobnie nie.
Znamy twoje imię! To $username "); } ?>
Liczba stron odwiedzonych w tej sesji: "); ?> Możesz obejrzeć tylko stron w czasie sesji.
To jest łącze do ">tej samej strony. Przejście tutaj zwiększa liczbę stron odwiedzonych w czasie sesji, ale nie robi wiele więcej.
Tutaj jest formularz, w którym, jeżeli chcesz, możesz podać nam swoje imie. Nie sprzedamy go nikomu.
Nazywam
się:
< I N P U T TYPE=TEXT S I Z E = 2 0 NAME=posted_username>
if (Spagecount >= Spagecount__limit) session_destroy(); ?>
Ten przykładowy kod realizuje za pomocą wywołania funkcji obsługi sesji następujące zadania: 1. Wywołuje session_start ( ) w celu nakłonienia PHP do odszukania wcześniej istniejącej sesji —jeżeli nie zostanie odnaleziona żadna sesja, tworzony jest nowy identyfikator (chociaż kolejną funkcją jest session_register ( ) ,
która troszczy się również o rozpoczęcie sesji, jeżeli nie było wywołania session_start ()).
2. Użyta jest funkcja session_register ( ) , aby zarejestrować zmienne 'username' i 'pagecount'. Są nadal niezainicjowane po tym wywołaniu. 3. Zwiększamy wartość $pagecount — ponieważ była ona niezainicjowana, jest interpretowana jako 0; po tej operacji będzie miała wartość 1. 4. Za pomocą funkcji session_id() drukujemy wartość identyfikatora sesji (w przypadku produkcyjnego serwera jest to działanie niezwykłe — nie jest to informacja przeznaczona dla użytkownika). 5. Jeżeli strona wysłała do samej siebie zmienną $posted_username (przy uży-
ciu formularza), nazwa jest zapamiętywana w zarejestrowanej zmiennej Susername. W wyniku Susername jest przenoszone do przyszłych wywołań
skryptu, nawet gdy $posted_username nie zostanie przeniesione. 6. Na koniec ustalamy, że użytkownik może odwiedzić określoną liczbę stron, zanim sesja zostanie rozpoczęta od nowa. Używamy funkcji session_destroy ( ) , aby usunąć wszystkie dane o zmiennych sesji, co oznacza, że rozpoczynamy od nowa zarówno z $pagecount, jak i $username.
Rysunki 25.1, 25.2 i 25.3 pokazują wygląd okna przeglądarki na pierwszym etapie wykonywania skryptu z wydruku 25.1, następnie po wysłaniu nazwy przez formularz i po przejściu przez łącze. W tym przypadku przeglądarka obsługuje cookie, więc w adresie URL nie pokazują się żadne informacje o sesji.
Zagadnienia konfiguracji *
Zmienne z tabeli 25.2 należy ustawiać w pliku php.ini, można je również podejrzeć za pomocą funkcji php_inf o ( ) . W tabeli zamieściliśmy opis i „typowe" wartości (niektóre wartości domyślne są zależne od platformy).
Pułapki i wykrywanie usterek Jeżeli masz kłopoty z sesjami, na początku upewnij się, że obsługa sesji istnieje. Spróbuj załadować przykładowy kod obsługi sesji T. ftp.helion.pl/przyklady/php4bi.zip, jeżeli nadal będzie występował błąd, szukaj wcześniej.
424___________________________________Część
Rysunek 25.1. Strona testowania sesji po uruchomieniu
Rysunek 25.2. Strona
testowania sesji
po przetworzeniu danych z formularza
III
*
Techniki
zaawansowane
Rozdział 25. » Sesje
425
Rysunek 25.3.
Strona testowania sesji
po przejściu przez łącze
Tabela 25.2. Zmienne konfiguracji sesji
Typowa wartość
Opis
/tmp
Ścieżka do katalogu na serwerze, w którym zapamiętywane są pliki z wartościami zmiennych sesji
session. auto start
0
Gdy ma wartość 1 , sesje będą inicjalizowane automatycznie po uruchomieniu skryptu. Gdy ma wartość 0, nie będzie użyty kod sesji do czasu użycia
session. save handler
'files'
Ciąg określający metodę zapisywania zmiennych sesji. Inne metody nie sąjeszcze dobrze udokumentowane — zmienianie ich nie jest wskazane dla początkujących użytkowników
Zmienna php.ini session. save p a t h
w systemach Unix
session s t a r t ! ) lub session r e g i s t e r ! )
*
session . cookie lifetime
0
Określa czas, po jakim cookie stanie się nieważne, i w konsekwencji czas trwania sesji. Domyślną wartościąjest 0, co oznacza, że sesje trwają do czasu zamknięcia przeglądarki — każda inna liczba oznacza liczbę sekund dopuszczalnego czasu życia sesji
session. use cookies
1
Jeżeli ma wartość 1, mechanizm sesji będzie próbował przenosić identyfikator sesji poprzez ustawianie i sprawdzanie cookie (jeżeli przeglądarka odrzuci cookie, używane będą zmienne GET, POST). Jeżeli wartość ta wynosi 0, próba użycia cookie nie będzie podjęta
426___________________________________Część
III
»
Techniki
zaawansowane
Jeżeli sesje nie działają lub powodują błędy, sprawdź ścieżkę zwracaną przez session_save_path ( } i upewnij się, że katalog istnieje, a PHP może w nim zapisywać pliki. Jeżeli nie, powinieneś utworzyć go lub zmienić wartość 'session. save_path' w pl\kuphp.ini. Pamiętaj, że funkcje sesji, które jako argumentu wymagają nazwy zmiennej, nie oczekują początkowego $ w nazwie zmiennej. Jeżeli nagłówki HTTP nie są wysyłane, skrypt może wysyłać tekst (nawet pusty wiersz) przed wywołaniem funkcji session_start () lub session_register (). Odszukaj
w dołączanych plikach wszystkie puste wiersze lub przesuń funkcje obsługi sesji na początek pliku. W czasie testowania kodu związanego z sesjami pamiętaj wypróbować go zarówno
w przeglądarce obsługującej sesje, jak i w przeglądarce z zablokowaną obsługą. Jeżeli nie zobaczysz nazwy sesji w adresie URL łącza (na przykład: PHPSESSID) w przeglądarce nieakceprującej cookies, sesje nie działają, albo PHP nie jest odpowiednio skonfigurowany do przezroczystego przesyłania identyfikatora sesji za pomocą argumentów GET, POST.
Podsumowanie Sesje są użyteczne w sytuacjach, gdy chcesz śledzić działania użytkownika w przypadku interakcji trwającej dłużej niż wykonanie jednego skryptu. Jeżeli prezentowana zawartość strony zależy od działań podejmowanych na poprzedniej, kod powinien zapamiętywać i przenosić te informacje w sposób, który umożliwia odróżnienie poszczególnych użytkowników. Ponieważ protokół HTTP jest protokołem bezstanowym, prowadzi to
zastosowania technik zastępczych — zwykle albo ukrytych zmiennych (które są niestety kłopotliwe), albo cookies (niektóre przegładarki klientów ich nie obsługują).
Implementacja sesji w PHP hermetyzuje te skomplikowane zagadnienia. Identyfikatory sesji są tworzone i rozprowadzane w sposób automatyczny, a mechanizm rejestracji pozwala programiście dołączać dowolne dane PHP do sesji. Poza początkowym dołączeniem się do sesji i zarejestrowaniem zmiennych, które powinny zostać rozpropagowane poza bieżącą stronę, użycie sesji jest dla programisty przejrzyste.
Rozdział 26.
Cookie i HTTP W tym rozdziale: * Ustawianie i odczytywanie cookie ** Wysyłanie surowych nagłówków HTTP
* Używanie przekierowań w przeglądarkach HyperText Transfer Protocol (HTTP) jest,językiem", którego serwery i klienci WWW używają do komunikacji między sobą. Gdy odwiedzasz witrynę WWW, powodujesz zainicjowanie dialogu w Internecie przy użyciu HTTP (lub jego wariantu, przykład bezpiecznego HTTPS). Zwykły użytkownik WWW nie musi przejmować się szczegółami HTTP, ale nie dotyczy to programistów. Nasz przykłady w przeważającej części korzystały z PHP w celu utworzenia skryptu wykonywanego na maszynie klienta lub dokumentu HTML, wyświetlanego w przeglądarce użytkownika. HTTP jest pojazdem przeznaczonym do przesyłania wywołań do naszego skryptu, następnie transportującym odpowiedź w postaci gotowej do wyświetlenia u użytkownika. W tym rozdziale przedstawimy kilka technik, które zależą od innych elementów interakcji klient-serwer, takich jak zapisywanie danych w cookie w komputerze klienta lub jawne zastosowanie nagłówków HTTP do identyfikacji użytkownika lub przekierowania na inną stronę WWW. Funkcje PHP pozwalające na korzystanie z bezpośredniej komunikacji HTTP są bardzo proste i jest ich stosunkowo niewiele — problemy wynikaj ą raczej z ograniczeń nałożonych na sam protokół.
Cookie Cookie to mała cząstka informacji przechowywana w komputerze klienta, albo w pamięci przeglądarki, albo jako mały plik zapisany na dysku. Zawiera on parę nazwa i wartość. „Ustawianie cookie" oznacza skojarzenie wartości z nazwą i zapisanie tej pary w komputerze klienta. „Pobieranie" albo „odczytywanie" polega na użyciu nazwy w celu uzyskania skojarzonej z nią wartości (przeczytaj część „Cookie i prywatność", w którym opisaliśmy kontrowersje związane z używaniem cookie}.
Część III » Techniki zaawansowane
428
Jako generalną zasadę powinniśmy przyjąć, że zapisujemy dane w cookie po stronie klienta tylko wtedy, gdy nie można zapisać ich na serwerze. To nie tylko grzeczność. Występują ograniczenia w korzystaniu przez serwer z dysku klienta (zwykle jeden serwer WWW może zapisać do 20 cookies w komputerze klienta). Jeżeli musisz zapamiętać wiele danych, zastanów się nad zapisaniem w cookie tylko identyfikatora umożliwiającego odszukanie reszty danych na serwerze.
W PHP cookies są ustawiane za pomocą funkcji setcookie ( ) , czytane są nieomal automatycznie. Oznacza to, że wszystkie cookies ustawione przez twój serwer są pobierane do strony jako zwykłe zmienne (podobnie jak zmienne GET/POST). Wiele zastosowań cookies jest związanych ze śledzeniem sesji — pamiętaniem jakiejś części danych w czasie nawigacji. Jeżeli chcesz użyć cookie do takiego właśnie zastosowania i używasz PHP 4, powinieneś pomyśleć o zastosowaniu wbudowanych funkcji obsługi sesji, które przedstawiono w poprzednim rozdziale. Nie tylko oferują lepszy poziom abstrakcji, ale posiadają również wbudowany mechanizm zastępczy, uruchamiany w przypadku odrzucenia cookie. Stosowane jest wtedy przesyłanie danych za pomocą argumentów GET/POST.
Funkcja setcookie() Istnieje tylko jedna funkcja związana z obsługą cookie — setcookie ( ) . W tabeli 26.1 zamieszczone są argumenty funkcji. Kolejność w tabeli odpowiada kolejności w wywołaniu funkcji. Wszystkie argumenty oprócz pierwszego są opcjonalne. Szczegóły reprezentowania czasu używanego jako argument expire zamieszczone są w rozdziale 13. „Funkcje systemu operacyjnego i dostępu do plików". Szczególnie interesujący będzie opis funkcji time ( ) i m k t i m e ( ) . Wywołanie setcookie o powoduje wysłanie odpowiedniego nagłówka HTTP. Nie da się teego wykonać, jeżeli wcześniej wysłany został normalny kod strony (nawet jeżeli zawiera on tylko jedną spację lub pusty wiersz).
Przykłady Zamieścimy teraz kilka przykładów użycia setcookie ( ) z komentarzem. setcookie('membername', 'timboy');
Rozdział
26.
»
Cookie
I
HTTP______________________________________429
Tabela 26.1.
Argumenty setcookief)
argumentu
Nazwa
Spodziewany typ
Znaczenie
name
string
Nazwa cookie (analogiczna do nazwy zmiennej)
value
string
Wartość zapisywana w cookie (analogiczna do wartości przypisywanej do zmiennej). Jeżeli argument ten nie zostanie podany, cookie o nazwie określonej przez pierwszy argument zostanie skasowane
expire
int
Określa czas, po którym cookie powinno się unieważnić. Wartość 0 (domyślna) oznacza, że cookie ma istnieć aż do zamknięcia przeglądarki.
Każda inna wartość jest interpretowana jako czas absolutny (taki, jak zwraca funkcja mktime ( ) ), kiedy ważność cookie wygaśnie path
string
Domyślnie każda strona umieszczona w głównym katalogu witryny WWW
może widzieć (i może ustawić) cookie o określonej nazwie. Ustawienie
tego parametru na podkatalog (na przykład "/mysteryguide") pozwala na odróżnienie cookie ustawionych przez różne części tej samej witryny WWW domain
string
W normalnych przypadkach nie jest sprawdzana domena wywoływana przez klienta. Jeżeli zostanie ustawiony ten argument, domena musi się zgadzać. Jeżeli np. ten sam serwer udostępnia mysteryguide.com
i sciencebookguide.com, to kod witryny może stwierdzić, że inna witryna
nie odczytuje (lub nie ustawia) używanego przez niącoofae dzięki
ustawieniu tego argumentu jako "mysteryguide.com" secure
int (0 lub l )
Wartością domyślnąjest 0. Jeżeli ustawimy wartość argumentu na 1, cookie będzie wysyłane tylko przez bezpieczne połączenie (https). Połączenie takie musi być wcześniej uruchomione
Wywołanie powyższe ustawia cookie o nazwie membername i o wartości timboy. Ponieważ nie ma żadnych innych parametrów oprócz pierwszych dwóch, cookie przetrwa tylko do zamknięcia przeglądarki i będzie dostępne dla wszystkich kolejnych wywołań z tego serwera, niezależnie od nazwy domeny i od miejsca w hierarchii katalogów serwera WWW. Cookie będzie również dostępne niezależnie od tego, czy mamy bezpieczne połączenie. setcookie f ' membername', ' troutgirl' , timeO -t- 86400, "", "www.troutworks.com", l);
To wywołanie ustawia cookie o wartości ' t r o u t g i r l ' nadpisuje wartość z poprzedniego przykładu, jeżeli została ustawiona na wcześniejszej stronie. Czas, po którym ważność cookie zakończy się, jest ustawiony na 86400 sekund (l dzień = 60 sekund * 60 minut * 24 godziny). Ścieżka nie jest podana (przekazany został pusty ciąg), więc cookie może być czytane niezależnie od położenia strony w hierarchii katalogów. Argument host jest ustawiony na ' www. troutworks. com' co oznacza, że kolejne strony nie odczytają tego cookie, chyba że użytkownik wyśle żądanie do tego właśnie komputera. Ostatni argument określa, że cookie może być czytane i zapisywane tylko poprzez bezpieczne połączenie (jeżeli połączenie używane przez tę stronę nie jest bezpieczne, cookie nie będzie w ogóle ustawione).
Część III » Techniki zaawansowane
430
Wielokrotne wywołania setcookieo będą zwykle interpretowane w odwrotnej kolejności, niż znajdują się w skrypcie PHP, ale nie wszystkie przeglądarki tak działają. Najlepszym rozwiązaniem jest nie ustawianie w jednej stronie dwóch takich samych cookies (wysyłanie cookie więcej niż raz jest zupełnie bezcelowe, ponieważ drugie wywołanie nadpisze poprzednią wartość). Jeżeli chcesz podać późniejsze argumenty setcookie o , pozostawiając poprzednie bez zmian, najlepiej podstawić pusty ciąg ("") w miejsce argumentu domain, ciąg zawierający znak ukośnika ("/") w miejsce ścieżki oraz O w miejsce czasu upływu ważności.
Usuwanie cookie Usuwanie cookie jest łatwe. Po prostu wywołaj setcookie (nazwa_cookie) bez podanego drugiego argumentu, które nie przypisuje do wartości cookie pustego ciągu,
ale usuwa je.
Cookies i prywatność
Cookies zawsze budziły kontrowersje z powodu naruszania prywatności. W czasie pisania tej książki DoubleClick (internetowa agencja reklamowa) była krytykowana za plany skorelowania danych pochodzących z cookie z danymi zawartymi w olbrzymiej bazie danych z nazwami konsumentów, adresami i przyzwyczajeniami. Istnieje obawa, że jeżeli klient poda swoje dane w witrynie, wypełniając formularz, i pozwoli na ustawienie cookie, wszystkie inne witryny porównujące swoje zapisy z wcześniejszymi witrynami mogą w ten sposób identyfikować użytkowników (i poznać w ten sposób wiele innych danych). Jeżeli taka praktyka stałaby się powszechna, każda witryna handlu elektronicznego, którą odwiedzasz, mogłaby poznać nie tylko twoje nazwisko, adres i zakupione towary, ale również listę innych odwiedzanych stron. Cookies są również rozsądnym obejściem bezstanowości protokołu HTTP. Istnieje wiele powodów, żeby rozciągać interakcję pomiędzy klientem i serwerem na kilka kolejnych stron, zamiast pakować wszystko do jednego wywołania. Jako projektant witryny możesz zdecydować się na użycie do tego celu cookie, ponieważ nie występuje tutaj bezpośrednia ingerencja w prywatność użytkownika. Wielu użytkowników tak ustawia swoje przeglądarki, aby odrzucały wszystkie cookies (pamiętaj, że jest to związane nie tylko z prywatnością, ale również z dostępem do ich własnych dysków). Każdy kod na serwerze powinien odpowiednio obsługiwać odrzucenie cookies przez klienta, a witryny powinny posiadać łatwe do odszukania opisy zasad szanowania prywatności, aby użytkownik wiedział, czego się może spodziewać.
Rozdział 26.
» Cookie I HTTP______________________________________431
Odczytywanie cookie Cookies automatycznie pojawiają się jako zmienne globalne strony, jeżeli uda się ich odczytanie. Na przykład ustawienie cookie: setcookie('membername', 't imboy');
spowoduje, że na kolejnych stronach będziesz mógł łatwo wypisać tę wartość w następujący sposób: print("Wartość membername wynosi $membername ");
Jeżeli ustawiasz cookie w skrypcie, ustawienie to zostanie wykonane
po wysłaniu całej strony do klienta zbyt późno, aby skorzystać z zalet automatycznego odczytywania cookie na tej stronie. Oznacza to, że odpowiednia zmienna globalna zostanie ustawiona dopiero przy następnym żądaniu strony.
Poniższy przykład nie zadziała tak, jak mógłbyś się spodziewać: setcookie('membername', 'timboy'); print ( "Ustawiłem cookie! Teraz odczytam wartość "); // (ŹLE - wartość zmiennej $membername będzie pusta) print("Wartość membername wynosi Smembername ");
Dzieje się tak, ponieważ, jak wspomnieliśmy w ostatniej wskazówce, cookie nie zostanie ustawione dopóki odpowiednie nagłówki HTTP nie dotrą do klienta. Ponieważ w przykładzie taka sytuacja nie zaszła, zmienna $membername nie została zainicjowana i będzie zawierała prawdopodobnie pusty ciąg.
Poniższy przykład pokazuje prawidłową obsługę takiego przypadku: $cookievalue = 'timboy'; setcookie('membername', $cookievalue); print( "Ustawiłem cookie, aby użyć go w kolejnych stronach ");
// (DOBRZE - wypisujemy wartość zainicjowanej zmiennej) print("Wartość membername wynosi $cookievalue ");
Kolejne skrypty załadowane do tej samej przeglądarki będą mogły odwoływać się do zmiennej $membername.
Wspominaliśmy już o problemie naruszenia prywatności użytkownika przyjmującego cookie z serwera. Trzeba zauważyć, że są to zagrożenia również innego rodzaju. Jeżeli piszesz skrypt, który zależy od integralności danych zawartych w cookie, powinieneś pamiętać, że sprytny użytkownik może je zmienić i ustawić w nich dowolne wartości. W rozdziale 31. „Bezpieczeństwo i kryptografia" znajduje się opis technik szyfrowania ważnych danych, nawet tych w cookie.
432___________________________________Część III » Techniki zaawansowane
Zmienne GET, POST i cookie Autorzy tej książki z całego serca popieraj ą decyzję projektantów PHP, aby pozwolić na natychmiastowy dostęp do wielu rodzajów informacji dzięki zmiennym globalnym. Argumenty GET i POST, wartości cookie i różne parametry konfiguracji oraz środowiska
po prostu są gotowe do użycia bez zbędnych wymogów formalnych. Oczywiście nieuniknioną wadą globalnej dostępności jest kolizja nazw — w jakimś momencie prawdopodobnie uwikłasz się w błędy wynikające z tego, że jakaś zmienna globalna będzie przypisana lub jej wartość zostanie niespodziewanie zmieniona. Nie jest to problem ze skryptem (który zwykle robi to, czego po nim oczekiwałeś w obrębie swojej przestrzeni nazw, ponieważ żadne zwykłe przypisanie do zmiennej nie jest przenoszone do innych
skryptów), ale z inną częścią oprogramowania.
Wszystkie wartości zmiennych GET, POST oraz cookie są dostępne jako globalne zmienne strony już na początku skryptu. Jeżeli dwa lub więcej z tych źródeł posiada zmienne o tej samej nazwie, jedna lub więcej wartości zmiennej zostanie nadpisana. Domyślną kolejnością nadpisywania jest: GET, POST, cookie — co oznacza, że argumenty POST nadpiszą wszystkie zmienne GET o takiej samej nazwie, a wartości cookie
nadpiszą wartości argumentów POST.
Przykład: kolejność nadpisywania zmiennych Na wydruku 26.1 zamieszczony jest kod korzystający z wszystkich trzech źródeł
zmiennych globalnych. Przykład ten pokazuje mechanizm domyślnego nadpisywania w działaniu.
Wydruk 26.1. Kolejność nadpisywania argumentów GET, POST i cookie_____ __ __ ______
W kodzie tym istnieją trzy możliwe sposoby ustawienia zmiennej globalnej $VarSource: ze zmiennej POST, ze zmiennej GET oraz z cookie. Nieco pokrętny może się wydawać sam początek kodu, który ustawia cookie 'VarSource', jeżeli zmienna $ VarSource
Rozdział 26.
»
Cookie
I
HTTP______________________________________433
nie jest ustawiona T. cookie, i usuwa cookie, jeżeli jest ustawiona. W przypadku domyślnej kolejności nadpisywania powoduje to kolejne ustawianie i usuwanie cookie w trakcie kolejnych przeładowań strony. Jedynym przeznaczeniem tej strony jest pokazywanie wartości zmiennej $varSource, o ile jest ustawiona, i pokazywanie formularza zawierającego argumenty GET oraz POST o tej samej nazwie (użycie GET i POST jednocześnie nie jest nielegalne, ale nieeleganckie). Rysunek 26.1 pokazuje wynik działania skryptu po pierwszym załadowaniu. Rysunek 26.1. Pierwsze załadowanie skryptu pokazującego kolejność nadpisywania
Przy pierwszym załadowaniu strony nie ma ona żadnych argumentów GET ani POST i mimo że zostało właśnie ustawione cookie, nie jest jeszcze dostępne w tym skrypcie. W wyniku tego zmienna $VarSource nie została ustawiona. Na rysunku 26.2 pokazany jest wygląd strony po naciśnięciu przycisku Wyślij za pierwszym razem. Tym razem zmienna $VarSource jest zainicjowana przez cookie, ponieważ zostało ustawione w czasie pierwszego załadowania strony. Obecnie w rym konkretnym przypadku wszystkie źródła danych (GET, POST i cookie) dostarczaj ą wartości zmiennej $VarSource, nadpisywanej w takiej właśnie kolejności. Rysunek 26.2.
Wynik dzialania
skryptu
po pierwszym naciśnięciu Wyślij
434___________________________________Część
III
»
Techniki
zaawansowane
Jeżeli jeszcze raz przyciśniemy Wyślij, powinniśmy zobaczyć ekran pokazany na rysunku 26.3. Cookie zostało usunięte w czasie drugiego załadowania, więc wartość argu-
mentu POST nie jest nadpisywana. Zauważ, że w adresie URL znajduje się zmienna GET, ale za każdym razem jest nadpisywana. Rysunek 26.3 Wynik dzialania skryptu po drugim naciśnięciu Wyślij
Ustawianie kolejności nadpisywania Domyślną kolejnością nadpisywania wartości w czasie tworzenia zmiennych globalnych z różnych źródeł HTTP jest GPC, skrót od GET, POST, cookie. Jeżeli posiadasz własną instalację PHP i zdecydujesz, że kolejność ta nie jest odpowiednia, możesz ją zmienić, edytując p\ikphp.ini i zmieniając wartość dyrektywy gpc_order z "GPC" na cokolwiek innego. Zmienne globalne pochodzące z różnych źródeł są ustawiane w kolejności liter w tym ciągu, co powoduje, że późniejsze przypisanie nadpisuje poprzednie. Jeżeli opuścisz literę, odpowiadające jej źródło danych nie będzie brało udziału w przypisywaniu wartości do zmiennych globalnych. Na przykład, jeżeli ustawisz dyrektywę gpc_order na PG, wartości POST będą nadpisywane przez wartości zmiennych GET o tej samej nazwie, a wartości zapisane w cookie nie będą brane pod uwagę w czasie tworzenia zmiennych globalnych.
Tablice zmiennych GET, POST i COOKIE W przypadku, gdy problemy nachodzenia na siebie przestrzeni nazw zmiennych są trudne do opanowania, można odczytać wartości zmiennych bezpośrednio z ich źródła
dzięki użyciu tablic HTTP_GET_VARS, HTTP_POST_VARS i HTTP_COOKIE_VARS. Każda z nich jest tablicą asocjacyjną, która zawiera nazwy i wartości zmiennych pochodzących z odpowiedniego źródła, niezależnie od wykonywanego później przypisania do zmiennych globalnych. Dla przykładu, skrypt zamieszczony na wydruku 26. l pokazuje zawartość zmiennej globalnej $VarSource, której wartość zależy od kolejności nadpisywania. Jeżeli potrzebujesz wartości z określonego źródła danych HTTP, możesz użyć wartości HTTP_GET_VARS['VarSource ' ], HTTP_POST_VARS['VarSource'] lub HTTP COOKIE V A R S [ ' V a r S o u r c e ' ] •
Rozdział 26. « Cookie i HTTP
435
PHP przechowuje wartości zmiennych HTTP w tablicach tylko w przypadku, gdy zmienna konfiguracji track_vars ma wartość TRUE. Jest ona tak ustawiana w przypadku kompilacji PHP z (domyślną) opcją -enabie-track-vars. Można również zmienić to ustawienie, modufikując wartość tej zmiennej w pliku php.ini.
Pułapki cookie Trudno jest zrobić coś źle używając PHP. Ustawienie cookie wymaga wywołania tylko jednej funkcji (set_cookie ( ) ) , a odczytanie cookie nie wymaga podejmowania żad-
nych działań (ponieważ wartość cookie automagicznie pojawia się jako zmienna globalna). Czy można sobie wyobrazić coś łatwiejszego? Typowe problemy są związane z samym protokołem HTTP.
Wcześniejsze wysłanie danych Najczęstszym błędem przy obsłudze cookie jest próba ustawienia cookie po wysłaniu jakichkolwiek danych zawartych na stronie HTML (powtórzymy to jeszcze raz w tym rozdziale, ponieważ odnosi się to również do innych bezpośrednich manipulacji z protokołem HTTP i jest przyczyną większości problemów przy uruchamianiu). Powodem błędnego działania jest to, że HTTP wymaga wysłania nagłówka przed zawartością samej strony HTML — nie mogą być wymieszane. Przed wygenerowaniem jakiejkolwiek zawartości strony PHP musi wiedzieć o wszystkich specjalnych nagłówkach i wtedy wysyła je przed rozpoczęciem transmisji zawartości strony HTML. Jeżeli zdarzy się, że cookie (lub dane o innym nagłówku) wystąpi później, zostanie wygenerowany błąd. Łatwo napisać kod łamiący tę zasadę. Spójrz na następujący przykład:
Pozornie prosta strona ustawiająca cookie
Strona jest tak prosta, że nic złego nie może się zdarzyć
Gdy załadujemy ten skrypt, otrzymamy błąd „cannot add header information" (nie można dodać danych nagłówka). Problem powodowany jest pierwszym znakiem pliku: spacja przed „
436___________________________________Część
III
»
Techniki
zaawansowane
Jeżeli kiedykolwiek zdarzy się ten błąd, dosyć łatwo odszukać jego przyczynę. Spróbuj najpierw przesunąć kod związany z HTTP na początek pliku. Jeżeli mimo tego otrzymasz komunikaty o błędach, musisz prześledzić kod wstecz od miejsca, w którym wystąpił błąd, aż do początku pliku. Gdzieś pomiędzy początkiem pliku a miejscem wystąpienia błędu znajduje się albo kilka znaków interpretowanych w trybie HTML, albo konstrukcja PHP wypisująca dane. Jeżeli dołączałeś jakieś pliki przed miejscem wystąpienia błędu, sprawdź, czy występują w nich znaki przed znacznikiem startowym PHP lub po znaczniku zamykającym blok PHP. Nasze powtarzające się ostrzeżenia na temat kolejności danych w nagłówkach HTTP i zawartości strony są ważne dla wszystkich wersji PHP 3 oraz dla PHP 4 do wersji beta 3. Jednak projektanci PHP 4 dołożyli opcję „buforowania wyjścia", która ma za zadanie zapamiętać fragmenty danych PHP, aby wysłać je razem, a nie w momencie wygenerowania. Oznacza to, że PHP sam zajmuje się wstrzymywaniem zawartości strong do momentu wysłania wszystkich nagłówków HTTP. Powinieneś przetestować możliwości buforowanego wyjścia w twojej wersji PHP, próbując uruchomić przykład naruszający reguły kolejności, zamieszczony w tym rozdziale (jeżeli będzie on działał bez problemów, wyjście jest buforowane). Możesz również obejrzeć wynik funkcji phpinfoo, szukając wzmianki o buforowaniu — jeżeli się tam znajduje, będziesz mógł zmienić to ustawienie w pliku php.ini.
Interpretacja w odwrotnej kolejności Wywołania setcookieO są realizowane w odwrotnej kolejności, niż znajdują się w skrypcie PHP. Oznacza to, że para kolejnych wywołań prawdopodobnie usunie cookie, ponieważ wyrażenie usuwające cookie będzie wykonane jako drugie. setcookie("mycookie"); // usuń poprzednia wartość (ŹLE) setcookie("mycookie", "newvalue"); // ustaw nową wartość (ŹLE)
Zwykle nie ma potrzeby usuwania cookie przed ustawieniem go na inną wartość — po prostu ustaw nową wartość. Oznacza to, że myląca odwrotna interpretacja wywołań setcookie o nie powinna zwykle mieć znaczenia.
Odrzucenie cookie Na koniec musimy ostrzec, że setcookie ( ) nie gwarantuje, że cookies będą przyjęte przez przeglądarkę — setcookieO próbuje tylko wysłać odpowiedni nagłówek HTTP. To, co stanie się później w komputerze klienta, może zależeć od tego, czy klient
ma odpowiednio nową przeglądarkę, która potrafi obsługiwać cookie, albo że użytkownik z rozmysłem zablokował przyjmowanie cookie.
Funkcja setcookie ( ) nawet nie zwraca wartości wskazującej na zaakceptowanie lub odrzucenie cookie. Jest to związane z synchronizacją pomiędzy wykonaniem skryptu
Rozdział 26. » Cookie i HTTP______________________________________437
a samym protokołem HTTP. Po pierwsze skrypt wykonuje się (włączając w to wywołanie setcookie ( ) ) dając w wyniku kompletną stronę wraz z nagłówkami HTTP. Wynik ten jest wysyłany do komputera klienta. W tym momencie przeglądarka decyduje, w jaki sposób zareagować na próbę ustawienia cookie. Dlatego skrypty muszą zawsze być napisane w sposób zapewniający sensowne działanie w przypadku niepowodzenia funkcji setcookie ( ) . Częstą techniką jest ustawianie cookie o nazwie „CookiesOn" i sprawdzanie na kolejnych stronach, czy zmienna $CookiesOn jest ustawiona.
Wysyłanie nagłówków HTTP Funkcja setcookie ( ) stanowi otoczkę do użycia odpowiednich nagłówków HTTP. PHP posiada dodatkowo funkcję header ( ) , która może być użyta do wysłania surowych nagłówków HTTP. Możesz za jej pomocą napisać własną funkcję ustawiającą cookie. Można jej użyć do korzystania z innych funkcji kontrolowanych przez nagłówki.
Składnia funkcji header ( ) jest tak prosta: wymaga jednego argumentu, którym jest ciąg zawierający nagłówek do wysłania. Wszystkie ostrzeżenia na temat wysyłania HTTP przed zawartością strony mają również zastosowanie do funkcji header o. Jeżeli nie masz PHP 4 z włączoną funkcją buforowania wyjścia, wszystkie wywołania header () muszą poprzedzać dane HTML ze skryptu, nawet jeżeli dane te to jedna spacja bądź pusta linia.
Przykład: przekierowanie Jednym z użytecznych nagłówków HTTP jest nagłówek „Location:", który może służyć do przekierowania. Należy podać pełny adres URL po ciągu „Location:" i przeglądarka rozpocznie odczytywanie danych z tego adresu. Na przykład: Strona dla wszystkich
Witaj!
Witamy wszystkich na tej stronie, nawet mężczyzn! Opowiedzcie nam o sobie.
Jeżeli wpiszemy tylko adres URL tej strony (http://www.troutworks.com/phpbook/ch26/ inclusive.php), zobaczymy stronę będącą wynikiem kodu HTML zawartego na dole skryptu. Jeżeli jednak dodamy argument GET (http://www.troutworks.com/phpbook /ch26/inclusive.php?gender=kobieta), zostaniemy skierowani do całkowicie innej stro-
438________________________________Część III » Techniki zaawansowane
ny. Zauważ, że różni się to od selektywnego importowania zawartości przy użyciu wyrażenia include — przeglądasz stronę o zupełnie innym adresie URL, niż wpisałeś w oknie przeglądarki. Ten rodzaj przekierowaniajest użyteczny w przypadku, gdy chcesz podzielić swoją witrynę WWW na warunkowe „gałęzie" bez konieczności wybierania przez użytkownika
różnych łączy.
Przykład: uwierzytelnianie HTTP Innym użytecznym zastosowaniem HTTP jest możliwość zażądania, aby przeglądarka zapytała w oknie dialogowym o nazwę użytkownika i hasło. Jest to realizowane przez nagłówek www-aut hen t i ca t e, w sposób pokazany na przykładzie:
$the__right_user = 'user1; // tylko przykład! Nie zalecane Sthe_right_password = 'password'; //tylko przykład! if(!isset($PHP_AUTH_USER))
($PHP_AUTH_PASSWD == 'password')) // patrz ostrzeżenie poniżej print("Możesz wejść "); else print("Nie jesteś tu mile widziany ");
?>
}
Po pierwszym załadowaniu tego skryptu (z użyciem odpowiedniej przeglądarki i wersji serwera) na ekranie pokaże się okno dialogowe. Po wprowadzeniu przez użytkownika
informacji do okna skrypt zostanie powtórnie automatycznie wywołany, z ustawionymi
wartościami zmiennych $PHP_AUTH_USER (nazwa użytkownika), $PHP_AUTH_PASSWD (wprowadzone hasło) oraz $PHP_AUTH_TYPE (zmienna ta będzie zawierała ciąg „Basic", ponieważ w PHP dostępny jest tylko taki typ uwierzytelniania). Korzystne jest, że
zmienne te pozostaną ustawione przez przeglądarkę we wszystkich kolejnych stronach, dlatego nie ma potrzeby używania innego mechanizmu do ich propagacji — wystarcza
tylko jedno pytanie o hasło w czasie sesji.
Poniższy kod zawiera tylko absolutne minimum potrzebne do demonstracji mechanizmu uwierzytelniania HTTP; nie jest modelem rzeczywistego systemu zabezpieczenia za pomocą kombinacji użytkownik i hasło. Nasz fragment kodu po prostu porównuje wartości zmiennych dostarczone przez przeglądarkę z zapisanymi w kodzie zmiennymi. Aby utworzyć prawdziwy system uwierzytelniania, powinieneś być może porównywać wynik zakodowania hasła z podobnie zakodowaną wersją zapisaną w bazie danych lub pliku. Rozdział 31. zawiera więcej informacji na temat kodowania i zagadnień bezpieczeństwa.
Rozdział 26. » Cookie i HTTP
439
Ten mechanizm uwierzytelniania działa tylko na serwerze WWW Apache z modułem PHP. Nie działa z wersją CGI PHP, ani z IIS/PWS.
Oprócz przekierowań i uwierzytelniania, zdolność do wysiania dowolnych nagłówków HTTP pozwala na precyzyjniejszą kontrolę nad wieloma aspektami relacji klient-serwer w HTTP, które są zwykle ustawiane domyślnie. Można na przykład określić dokładnie
czas wygaśnięcia i sposób buforowania strony lub wysyłać zwrotne kody statusu, które wskazuj ą klientowi, czy zwracana wartość powinna zostać zinterpretowana jako powodzenie czy niepowodzenie. Ponieważ PHP działa tylko jako kanał komunikacyjny do protokołu HTTP, większość z tych technik wykracza poza ramy tej książki.
Pułapki związane z nagłówkami Funkcja header ( ) podlega takim samym ograniczeniom jak funkcja setcookie(): nie można wysłać żadnych nagłówków po przesłaniu jakiejkolwiek zawartości strony, chyba że używasz późniejszych niż beta 3 wersji PHP 4, posiadającej opcję buforowania wyjścia. Powinieneś również wiedzieć, że użycie nagłówków wymaga nie tylko znajomości samego protokołu HTTP, ale również wiedzy o sposobie dostosowywania się doń różnych
przeglądarek. Jeżeli piszesz skrypty przeznaczone dla szerszego grona, powinieneś wykonać więcej testów przeglądarek za pomocą prostych skryptów generujących HTML. Większość przeglądarek posiada funkcję ostrzegania o próbie ustawienia cookie. Chociaż podczas przeglądania witryn wykorzystujących cookies taka sytuacja irytuje, stanowi świetne narzędzie do uruchamiania własnych skryptów używających cookies.
Podsumowanie PHP oferuje kilka sposobów skorzystania z możliwości protokołu HTTP, oprócz funkcji
tworzenia stron HTML, które są przesyłane dzięki HTTP. Funkcja setcookieO pozwala na ustawienie lub usunięcie cookie w przeglądarce użytkownika; wartości takie będą dostępne na kolejnych stronach jako zwykłe zmienne globalne.
Funkcja header ( ) pozwala na wysłanie dowolnego nagłówka HTTP. Może być używana na przykład do realizacji uwierzytelniania i przekierowań. Funkcje HTTP są bardzo proste, a główną przyczyną kłopotów jest sam protokół HTTP.
Jedną z komplikacji jest konieczność wysłania wszystkich nagłówków HTTP przed wysłaniem zawartości strony. Jest to bardzo częste źródło błędów w PHP 3 i w wersjach
beta PHP 4. Na szczęście w finalnej wersji PHP 4 wyjście HTTP jest buforowane
w sposób umożliwiający mieszanie nagłówków z zawartością.
440________________________________Część III » Techniki zaawansowane
Rozdział 27.
PHP i JavaScript W tym rozdziale: ** Tworzenie kodu JavaScript z PHP
* PHP jako zapas dla JavaScript * JavaScript statyczny kontra dynamiczny * Dynamiczna generacja formularzy W tym rozdziale spróbujemy połączyć najlepsze cechy skryptów wykonywanych na serwerze i na kliencie, łącząc PHP z JavaScript. Zaznaczymy granice użycia tych dwóch
języków skryptowych oraz przedstawimy wskazówki stylistyczne, które mogą być pomocne przy pisaniu kodu. Następnie przejdziemy do przykładów zastosowań, z których możesz skorzystać na własnej witrynie PHP. Jeżeli nigdy nie używałeś języka JavaScript, lektura tego rozdziału nie wystarczy do nauczenia się go. Zajmujemy się tutaj tylko tymi aspektami JavaScript, które istotnie wpływają na PHP. Jeżeli zastanawiasz się, co to jest zdarzenie onBiur, polecamy książkę Java Script, Autor: Arman Danesh, ISBN 83-86718-82-X.
Tworzenie kodu JavaScript w PHP Ponieważ PHP działa po stronie serwera, a JavaScript po stronie klienta, możesz spodziewać się kłopotów, stosując je razem na jednej stronie. Jednak podział ten powoduje, że są świetnym zespołem. Mimo że PHP potrafi tworzyć dynamicznie strony WWW, jest to jedynie język skryptowy serwera. Istnieje duża grupa zadań wykonywanych w witrynie WWW, które prawdopodobnie nie potrzebuj ą potęgi serwera i najlepiej jeżeli będą wykonane szybko — na przykład zmiana wyglądu kursora myszy w trakcie przesunięcia nad obiektem.
442___________________________________Część
III
»
Techniki
zaawansowane
JavaScript jest językiem skryptów, zorientowanym na klienta (istnieje wersja dla serwera, ale zakładamy, że już wybrałeś PHP), który może być szybko zintegrowany z PHP.
Również język skryptów klienta JavaScript (znany także jako Javascript, JScript, ECMAScript) posiada wiele ograniczeń. Na przykład nie potrafi komunikować się bezpośrednio z bazą danych, ani zmieniać się w czasie pracy. Co gorsza, nie można bazować na technologiach po stronie klienta, ponieważ mogą być zablokowane lub niedostępne w przeglądarkach użytkowników. Sumienni programiści skryptów muszą albo decydować o kodowaniu w najbardziej prawdopodobny sposób (i przyjmować narzekania ze strony mniejszości) lub utrzymywać kilka wersji witryny. PHP może pomóc w obejściu problemów niespójności technologii klienckich.
Pojedynek obiektów Prawdopodobnie największą różnicą pomiędzy JavaScript i PHP jest różnica w modelach obiektów. Są one całkowicie różne koncepcyjnie i używaj ą różnych stylów notacji. Niektórzy mogą uważać to za zaletę, ponieważ nie ma niebezpieczeństwa pomieszania podobnych obiektów (jest to możliwe na przykład w przypadku ASP i JavaScript). Wielu będzie uważało to za niekompatybilność, niewygodę lub wadę projektową. Jednak w każdym przypadku nie ma możliwości dostania się do tych samych obiektów za pomocą PHP i JavaScript. JavaScript jest konsekwentnie obiektowy. Każde wyrażenie wymaga podania obiektu i metody lub funkcji, może również posiadać metody obsługi zdarzeń. JavaScript używa do zapisu wyrażeń notacji z kropką (obiekt.metoda), podobnej do notacji stosowanych w C, Java i Microsoft VBScript.
Wadą modelu obiektowego JavaScript jest jego słaba standaryzacja, mimo że teoretycznie ECMA i W3C wprowadziły międzynarodowe standardy, praktycznie wszyscy producenci przeglądarek łamią podstawowe zasady lub dodają nowe. Biegli programiści JavaScript zużywają wiele energii, śledząc niekompatybilności i rozwiązania problemów dla różnych przeglądarek i platform. Jak wspominaliśmy w tej książce, klasy PHP są bardziej dodatkiem, modernizacją lub udogodnieniem niż istotną częścią języka. Używana notacja jest nazywana stylem „ze strzałką" lub „wskaźnikiem", styl taki jest spotykany czasami w kodzie C++ ($this->zmienna). Nie ma sposobu, aby używać notacji z kropką. Zmusza nas to szczerego przyznania, że klasy PHP prawdopodobnie nie rozwiną się do prawdziwego modelu obiektowego.
PHP nie analizuje wysyłanych danych Musisz wiedzieć i pamiętać, że dla PHP nie ma żadnego znaczenia, jakie dane wysyła na wyjście. Możesz użyć PHP do wysyłania czystego tekstu, HTML, XHTML, DHTML, JavaScript, XML, MathML, różnych formatów graficznych, CSS, XSL lub nawet ASP. Nie ma żadnej bariery technicznej, aby PHP produkował kod w C, jednak takie zastosowanie nie będzie prawdopodobnie zbyt szeroko rozpowszechnione.
Pamiętaj, że PHP nie zawsze daje w wyniku PHP — jego końcowym produktem jest zwykle kod uruchamiany przez inną aplikację, na przykład przeglądarkę.
Istnieje kilka sposobów wysłania kodu JavaScript za pomocą PHP. Najprostszym sposobem jest wyjście z trybu PHP w miejscach, w których musisz umieścić kod wykonywany w komputerze klienta. Jest to realizowane dokładnie tak samo, jak przejście do trybu HTML.
Nawet ten przykład nie pokazuje pełnej separacji pomiędzy PHP a JavaScript. Wiele
definicji kodu JavaScript jest zwykle umieszczanych na stronie HTML pomiędzy znacznikami i wywoływanych w części , a PHP jest zwykle używany w tej drugiej części.
Istnieją przypadki, kiedy nie chcemy wyłączać trybu PHP. W takich sytuacjach należy użyć wyrażeń PHP echo lub print, aby wysłać kod JavaScript. \n");
echo("\n"); echo("\n"); echo("Kolejny blok PHP");
?>
Styl taki jest również prawidłowy, ale jest dużo trudniejszy do zrozumienia. Jeżeli nie
jesteś doświadczonym programistą, powinieneś ograniczać stosowanie takiego stylu
tylko do sytuacji, w których wywołujesz predefmiowane funkcje JavaScript, np. zdarzenie onSubmit. Możesz mieć kłopoty, stosując znaczniki w stylu JavaScript (na przykład
PHP — analizator PHP może pogubić się przy rozpoznawaniu, który znacznik należy do którego znacznika
Rozdział 27. » PHP i JavaScript_____________________________________445
Plik o nazwie redirect.php posiada tylko jeden wiersz:
Możesz również skorzystać z takiego podziału zadań w przypadku sprawdzania poprawności formularzy. Jeżeli JavaScript jest włączony, możesz za jego pomocą sprawdzić, czy kod pocztowy ma 5 cyfr, numery telefonu mają 10 cyfr, adresy e-mail mają zarówno znak @, jak i '.'. Jeżeli JavaScript jest wyłączony, możesz za pomocą małego
skryptu PHP sprawdzić to samo po wysłaniu formularza przez użytkownika i zwrócić formularz z ostrzeżeniami w przypadku odnalezienia błędnych wartości. Kontrola formularzy przez JavaScript powinna być traktowana jako szybkie udogodnienie, nigdy zaś jako główne narzędzie kontrolne. Więcej szczegółów na ten temat znajduje się w rozdziale 31. „Bezpieczeństwo i kryptografia".
Innym rodzajem operacji na formularzach jest arytmetyka. Tutaj również możesz połączyć JavaScript z PHP w celu zabezpieczenia się z obu stron.
JavaScript statyczny kontra dynamiczny Statyczny JavaScript opisywany dotychczas w tym rozdziale jest użyteczny w wielu aplikacjach, ale trzeba go niestety modyfikować ręcznie. Jeżeli zdecydujesz się dodać stronę z programami do twojej witryny, musisz pamiętać, aby dodać odpowiednią pozycję w liście rozwijalnej. Możesz odpowiedzieć — nie ma problemu — ale takie błahostki stają się pożerającymi czas kłopotami, jeżeli tworzysz dużą i często odwiedzaną witrynę.
Za pomocą PHP i bazy danych można automatycznie uaktualniać niektóre fragmenty kodu JavaScript — można powiedzieć, dynamicznie. Zmienimy poprzedni przykład, aby skorzystać ze ściślejszej współpracy klient-serwer:
Menu nawigacji
Niewątpliwie zorientowałeś się, że takiej techniki można użyć również w przypadku prostego formularza JavaScript (używając zdarzenia onSubmit zamiast onChange). Pozwala to tworzyć bardziej elastyczne funkcje JavaScript dzięki zmienianiu przez PHP
wartości zmiennych w funkcji, zanim zostanie wysłana do przeglądarki. Jeżeli chcesz, możesz używać PHP do produkowania kodu JavaScript przy użyciu zmiennych z różnych źródeł danych.
Dynamiczna generacja formularzy Możesz jeszcze bardziej rozwinąć ten sposób programowania, tworząc serię dynamicznych list rozwijalnych, które zmieniają się w zależności od poprzednio wprowadzonych wartości. PHP pobiera dane z bazy i ładuje je do strony HTML, a JavaScript decyduje, które dane powinny być widoczne w różnych okolicznościach. W tym przykładzie będziemy chcieli pomóc użytkownikom odszukać dane na temat różnych samochodów. Lista modeli samochodów wyprodukowanych przez wszystkich pro-
ducentów jest dosyć druga, zbyt długa nawet dla dobrze zaprojektowanej listy rozwijalnej.
Dodatkowo nazwy samochodów są fonetycznie podobne. Jedyną możliwością logicznego zawężania wyboru jest umieszczenie listy producentów, po wybraniu określonego modelu ograniczenie ich listy tylko do wyprodukowanych przez wybranego producenta.
Potrzebna nam tabela bazy danych wygląda następująco (nie jest to odpowiedni projekt relacyjnej bazy danych, ale chcemy skupić się na JavaScript, a nie na bazie danych):
Rozdział 27. » PHP i JavaScript_____________________________________447
Używając tej bazy danych i skryptów serwera w PHP będziesz ograniczony do dwóch możliwości wyboru. Możesz stworzyć jedną dosyć dużą listę (albo w postaci listy roz-
wijalnej, albo w postaci strony) producentów i modeli, albo pokazać użytkownikowi dwa kolejne formularze. Jeżeli dodamy do tego JavaScript, możemy na górze strony
umieścić dwie listy rozwijalne, zmieniając zawartość drugiej listy na podstawie wyboru w pierwszej.
Nasz projekt podwójnej listy rozwijalnej bazuje na sprytnym kodzie JavaScript, którego autorem jest Andrew King. Dostępny jest pod adresem www.webreference.com na warunkach licencji Gnu.
Użyliśmy PHP, aby podłączyć się do bazy danych i przepisać dane do dwuwymiarowej tablicy, na której pracuje kod JavaScript. JavaScript jest odpowiedzialny za zachowanie się strony.
Wybierz producenta:
— -> < / B X / T D >
Wybierz model:
Jeżeli zmienisz lub dodasz jakieś dane w bazie danych, automatycznie zostanie zmieniona część JavaScript. Dynamiczna integracja nowych danych powoduje, że jest to świetne narzędzie pozwalające ograniczyć do minimum prace nad utrzymaniem strony.
Przesyłanie danych z JavaScript do PHP Na koniec zamkniemy pętlę danych, przesyłając dane z powrotem do PHP z użyciem JavaScript. Poniższy kod używa JavaScript do zaznaczenia co najmniej jednego pola wyboru. Przesyła on dodatkowo tablicę do skryptu PHP. Zdecydowaliśmy się tutaj na użycie ramek w celu maksymalnego przyspieszenia zmian. Dla pełnej przejrzystości wpisaliśmy ręcznie wszystkie wartości, zamiast odczytywać je ze źródła danych. sandwich_frames.html
main.html
LANGUAGE="JavaScript">
function deselectAHOthers (boxVals) (
for (var x = l; x < boxVals. length; x++) {
boxVals[x].checked=false;
)
}
Rozdział 27.
»
PHP i JavaScript_____________________________________451
function confirmOne(boxVals} { var count = 0; for (var x = 1; x < boxVals.length; x++) { if (boxVals[x].checked == false) { count++; 1 ( if (count == (boxVals.length - 1)) { boxVals[0].checked = true; } else (
boxVals[0].checked = false;
)
)
function toArray(boxVals) {
for (var x = 0; x < boxVals.length; x++) { var valArray = boxVals[x].name+"[]"; boxVals[x].name = valArray; )
t // -->
< B > Z a m a w i a m kanapkę z . . . < / B >
< T D VALIGN="top"XBRXBR>
Sery
Chleb
452___________________________________Część III
» Techniki zaawansowane
email_send.php
Ekran wysyłania poczty
mysql_connect("localhost", "root") ; mysql_select_db("mailinglist"); $list_length = 0; /* Zawiera warunek zatrzymania w przypadku wprowadzenia mniej niż 25 nazw. */
'SEmail[$list_length]', $Password)"; $result = mysql_query(Squery); $formsent = mail($Email[$list_length], "Informacja o użytkowniku i haśle", "Twoja nazwa użykownika to: SFirstName[$list_length] $LastName[Slist_length].\r\nUpewnij się, że jest tylko jedna spacja
pomiędzy imieniem i nazwiskiem w trakcie logowania.\r\nHaslo: SPassword.\nPowodzenia!", "From: mailinglist@sendhost\r\nReply-to:
?>
help@sendhost"); printC'Wynik dla Slist_length jest $f ormsent. \n") ; (
password_maker.inc
/* Wywoływana jest funkcja random_string. Używa ona random_char */
468___________________________________Część
III
»
Techniki
zaawansowane
function random_char($string) f $length = strlen($string); Sposition = mt_rand(0, $length - 1); return($string[$position]); } function random_string ($charset_string, Slength) ( $return_string = r a n d o m _ c h a r ( $ c h a r s e t _ s t r i n g ) ; for (Sx = 1; $x < Slength; $x+ + ) S r e t u r n _ s t r i n g .= r a n d o m _ c h a r ( S c h a r s e t _ s t r i n g ) ; return($return_string); ) // Inicjowanie generatora liczb losowych mt_srand((double)microtime() * 1000000); 5charset = "abcdefghijklmnopqrstuvwxyz"; ?>
Podsumowanie Poczta należy do najbardziej użytecznych i atrakcyjnych aplikacji internetowych. PHP
pozwala zarówno na wysyłanie, jak i odbieranie przesyłek e-mail z poziomu strony WWW. Jednak PHP nie jest wyspecjalizowanym programem, prawdopodobnie nie obsłuży dużej liczby przesyłek.
E-mail stanowi jedną z najbardziej skomplikowanych usług w większości domen. Zawiera wiele ruchomych części, brakuje mu też standaryzacji. Nie wiń za to PHP —jest to problem poczty. Jednym z najczęstszych zastosowań funkcji pocztowych PHP jest wysyłanie poczty
(często do siebie samego) z zawartością generowaną za pomocą formularza WWW. Jest to pewniejsze od łącza mai l to i pozwala na wprowadzenie ścisłej struktury danych.
Możesz również używać PHP do wysyłania małych paczek danych, korzystając z danych zapisanych w bazie. Jednak do wysyłania wielu listów potrzebny jest zarządca list wysyłkowych.
Rozdział 29.
PHPiXML W tym rozdziale:
«• CotojestXML? * Praca z XML * Dokumenty i DTD
«• DOM kontra SAX + Funkcje PHP dla XML: DOM + Funkcje PHP dla XML: SAX * Przykładowa aplikacja XML XML to jedno z najbardziej popularnych słów w dzisiejszym przemyśle oprogramowania, ale co ono oznacza dla szeregowego programisty PHP? Może być niezbędnym wstępem do lepszego Internetu — szybszego, bardziej interakcyjnego, mniej zaśmieconego i dostępnego. Przy użyciu PHP możesz łatwo zintegrować XML z arsenałem technologii tworzenia stron WWW, gdy tylko technologia ta dojrzeje.
Co to jest XML? XML jest skrótem od extensible Markup Language. XML jest uproszczoną formą SGML, Standard Generalized Markup Language, nie musisz jednak nic wiedzieć na temat SGML, aby używać XML. Definiuje on składnię dla strukturalnych dokumentów, które są czytelne zarówno dla komputera, jak i człowieka. Najłatwiejszym sposobem zrozumienia XML jest pomyślenie o tym, czego nie potrafi HTML. HTML jest również językiem bazującym na znacznikach, ale dokumenty HTML nie są strukturalne. Znaczniki HTML (technicznie nazywane elementami) i atrybuty są prostymi znacznikami identyfikacyjnymi dla przeglądarki. Na przykład para znaczników
i < / H l > oznacza nagłówek najwyższego poziomu. Przeglądarka interpretuje go jako tekst wyświetlany dużą, grubą i być może pochyłą czcionką. HTML
470___________________________________Część III
»
Techniki zaawansowane
nie wskazuje jednak, czy tekst pomiędzy tymi znacznikami jest tytułem strony, nazwiskiem autora, przywitaniem, obietnicą specjalnych cen sprzedaży. Jest to tylko fragment tekstu, który ma być napisany dużymi literami. Nasz opis XML musi być bardzo skrótowy (ponieważ jest to książka na temat PHP, a nie XML). Osobom, które chcą dowiedzieć się więcej na ten temat, polecamy książkę XML. Księga eksperta. Autor: Elliote Rusty Harold, ISBN: 83-7197-275-X. Mimo że książka ta nie jest poradnikiem na temat tworzenia aplikacji na bazie XML, przedstawimy podstawowe zasady i koncepcje.
Jedną z konsekwencji braku struktury HTML jest to, że wyszukiwarki dostają niewiele wskazówek, co jest ważne na każdej stronie lub jakie są relacje między poszczególnymi fragmentami tekstu. Aby to odgadnąć, używają różnych metod, ale żadna z nich nie jest odporna na błędy. Nadużywa się znaczników , witryny o treściach pornograficznych bardzo często umieszczają popularne, niezwiązane z prawdziwą zawartością
słowa kluczowe w nagłówkach, aby oszukać nieuważnych użytkowników WWW. Jeżeli XML stanie się wszechobecny, może wyeliminować wiele z tych problemów.
Załóżmy, że pracujesz dla witryny informacyjnej, która właśnie podpisała strategiczne porozumienie na temat wymiany informacji z dużym portalem. Podstawowy problem: w jaki sposób dostarczać dane. HTML nie jest odpowiedni do tego rodzaju zastosowań. Wiadomo, że projekt strony i technologie dostarczania danych są inne niż na twojej witrynie. Druga strona nie będzie mogła włączyć twojego HTML do swoich stron. Firmy używają różnych języków programowania, różnych baz danych, różnych edytorów HTML, różnych arkuszy stylu. Pośrednikiem może być format wymiany danych, łatwy do utworzenia w twoim środowisku programowym, zrozumiały dla obu stron i ich istniejącego oprogramowania, łatwy do konwersji do postaci odpowiedniej dla projektu
i potrzeb kontrahenta. XML to uniwersalny format wymiany danych.
Przykłady odpowiadają na pytanie, dlaczego XML. Jest to elastyczny format wymiany danych, który jest niezależny od oprogramowania, łatwo go analizować, pozwala dodać informacje na temat struktury danych. Następnym pytaniem na temat XML jest zwykle „do czego XML jest podobny". Faktycznie jest podobny do HTML. Prosty plik XML, jak ten pokazany na wydruku 29.1, jest łatwy do zrozumienia dla użytkowników HTML.
Jeżeli znasz HTML, jesteś w połowie drogi do poznania XML.
Rozdział 29. »
PHP i XML__________________________________________471
Oba są językami bazującymi na znacznikach, ale XML jest bardziej strukturalny od HTML.
Jak widzisz, znaczniki, atrybuty i hierarchiczna struktura, której użyliśmy, są podobne do tych w HTML. W XML każda para znaczników ( ... ) jest nazywana elementem. Tak jest też w HTML, ale większość użytkowników preferuje określenie „znacznik" (konstrukcja zaznaczająca element), a nie „element" (fragment konstrukcyjny oznaczany przez znaczniki). Możesz używać dowolnego terminu. Największą różnicą jest to, że znaczniki w XML są definiowalne i nie niosą ze sobą żadnej informacji na temat sposobu wyświetlania ani dla przeglądarki, ani dla innych programów wyświetlających.
Minimalne wymagania XML: * Musi wystąpić jeden element korzenia, który zawiera wszystkie inne elementy, podobnie do .. . w dokumencie HTML. Jest czasem nazywany elementem dokumentu. * Elementy muszą być hierarchiczne. Oznacza to, że dozwolone jest
YX/X>, a nie. W pierwszym przykładzie zawiera całość . W drugim przykładzie i zazębiają się. XML nie pozwala na zachodzenie na siebie znaczników. * Wszystkie elementy muszą być bezwzględnie zamknięte (w przeciwieństwie do HTML, w którym elementy mogą pozostać niedomknięte, np.