Datei wird geladen, bitte warten...
Zitiervorschau
Tytuł oryginału: Build Your Own Database Driven Web Site Using PHP & MySQL Tłumaczenie: Daniel Kaczmarek Projekt okładki: Mateusz Obarek, Maciej Pokoński ISBN: 978-83-246-5565-6 © Helion S.A. 2010 Authorized translation of the English edition of Build Your Own Database Driven Web Site Using PHP & MySQL, 4th Edition © 2009, SitePoint Pty. Ltd. This translation is published and sold by permission of O’Reilly Media, Inc., the owner of all rights to publish and sell the same. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: [email protected] WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/phmsw4.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie?phmsw4_ebook Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland.
• Poleć książkę na Facebook.com
• Księgarnia internetowa
• Kup w wersji papierowej
• Lubię to! » Nasza społeczność
• Oceń książkę
Dla moich Rodziców, Cheryl i Richarda, bez których nic nie byłoby możliwe.
Spis treści Przedmowa .................................................................................... 11 Rozdział 1. Instalacja ....................................................................................... 19 Własny serwer WWW .................................................................................................... 20 Instalacja w systemie Windows ...................................................................................... 21 Jednoczesna instalacja wszystkich komponentów ................................................. 21 Instalacja poszczególnych komponentów .............................................................. 26 Instalowanie w systemie Mac OS X ............................................................................... 34 Jednoczesna instalacja wszystkich komponentów ................................................. 34 Instalacja poszczególnych komponentów .............................................................. 37 Instalacja w systemie Linux ............................................................................................ 43 Instalowanie serwera baz danych MySQL ............................................................. 44 Instalowanie języka PHP ....................................................................................... 47 Zadania poinstalacyjne ................................................................................................... 53 O co zapytać dostawcę usług internetowych? ................................................................. 56 Nasz pierwszy skrypt PHP .............................................................................................. 57 Narzędzia gotowe, pora do pracy ................................................................................... 60
Rozdział 2. Wprowadzenie do systemu MySQL .................................................. 61 Wprowadzenie do baz danych ........................................................................................ 61 Logowanie się na serwerze MySQL ............................................................................... 62 SQL — Strukturalny Język Zapytań ............................................................................... 67 Tworzenie bazy danych .................................................................................................. 67 Tworzenie tabel .............................................................................................................. 68 Wstawianie danych do tabeli .......................................................................................... 70 Przeglądanie danych przechowywanych w bazie ........................................................... 72 Modyfikowanie danych przechowywanych w bazie ...................................................... 74 Usuwanie danych przechowywanych w bazie ................................................................ 75 Niech PHP sam napisze kod SQL ................................................................................... 75
Rozdział 3. Wprowadzenie do języka PHP ......................................................... 77 Podstawowe polecenia i składnia ................................................................................... 79 Zmienne, operatory i komentarze ................................................................................... 81 Tablice ............................................................................................................................ 82 Interakcja z użytkownikiem i formularze ....................................................................... 84 Struktury sterujące .......................................................................................................... 95
6
PHP i MySQL. Witryna WWW oparta na bazie danych Ukrywanie spoin ........................................................................................................... 103 Nie nagłaśniaj swoich decyzji w zakresie technologii ......................................... 104 Używaj szablonów PHP ....................................................................................... 105 Wiele szablonów, jeden kontroler ........................................................................ 107 Dajcie mi bazę danych! ................................................................................................ 110
Rozdział 4. Publikowanie w sieci WWW danych przechowywanych w bazie MySQL ............................................................................. 111 Idea działania ................................................................................................................ 111 Łączenie się z bazą MySQL za pomocą PHP ............................................................... 113 Wysyłanie zapytań SQL za pomocą języka PHP .......................................................... 118 Obsługa zbiorów wyników zapytania SELECT ........................................................... 120 Wstawianie danych do bazy ......................................................................................... 125 Usuwanie danych z bazy .............................................................................................. 133 Misja zakończona ......................................................................................................... 139
Rozdział 5. Projektowanie relacyjnych baz danych .......................................... 141 Umożliwianie autorom podpisywania kawałów ........................................................... 142 Prosta reguła: dane trzeba przechowywać osobno ........................................................ 143 Korzystanie z wielu tabel ............................................................................................. 147 Proste relacje ................................................................................................................ 151 Relacje typu wiele-do-wielu ......................................................................................... 153 Jeden za wszystkich, wszyscy za jednego! ................................................................... 155
Rozdział 6. Programowanie strukturalne w języku PHP .................................... 157 Dołączanie plików ........................................................................................................ 158 Dołączanie zawartości HTML ............................................................................. 158 Dołączanie kodu PHP .......................................................................................... 160 Rodzaje dołączania .............................................................................................. 164 Współużytkowane pliki dołączane ....................................................................... 165 Funkcje użytkownika i biblioteki funkcji ..................................................................... 167 Zasięg zmiennych i dostęp do zmiennych globalnych ......................................... 169 Programowanie strukturalne w praktyce: funkcje pomocnicze szablonów ................... 173 Najlepszy sposób .......................................................................................................... 176
Rozdział 7. System zarządzania zawartością ................................................... 177 Strona startowa systemu ............................................................................................... 178 Zarządzanie autorami ................................................................................................... 181 Usuwanie autorów ............................................................................................... 183 Dodawanie i edytowanie autorów ........................................................................ 186 Zarządzanie kategoriami ............................................................................................... 190 Zarządzanie kawałami .................................................................................................. 195 Wyszukiwanie kawałów ...................................................................................... 195 Dodawanie i edytowanie kawałów ....................................................................... 201 Usuwanie kawałów .............................................................................................. 211 Podsumowanie .............................................................................................................. 212
Rozdział 8. Formatowanie zawartości przy użyciu wyrażeń regularnych ............ 215 Wyrażenia regularne ..................................................................................................... 216 Formatowanie łańcuchów tekstu za pomocą wyrażeń regularnych .............................. 220 Wytłuszczenie i kursywa ..................................................................................... 221 Akapity ................................................................................................................ 223 Hiperłącza ............................................................................................................ 225 Domykanie znaczników ....................................................................................... 228 Składamy wszystkie elementy w jedną całość ..................................................... 229 Automatyczne zatwierdzanie zawartości ...................................................................... 232
Spis treści
7
Rozdział 9. Obsługa cookies i sesji oraz kontrola dostępu ............................... 233 Cookies ......................................................................................................................... 233 Obsługa sesji w PHP ..................................................................................................... 238 Prosty koszyk na zakupy ...................................................................................... 240 Kontrola dostępu .......................................................................................................... 248 Projekt bazy danych ............................................................................................. 248 Kod źródłowy kontrolera ..................................................................................... 252 Biblioteka funkcji ................................................................................................ 257 Zarządzanie hasłami i rolami ............................................................................... 266 Kolejne wyzwanie, czyli moderowanie kawałów ................................................ 273 Nieograniczone możliwości .......................................................................................... 275
Rozdział 10. Administrowanie bazą MySQL ....................................................... 277 phpMyAdmin ............................................................................................................... 278 Kopie zapasowe baz danych MySQL ........................................................................... 282 Wykonywanie kopii za pomocą programu mysqldump ....................................... 282 Kopie przyrostowe w binarnym dzienniku aktualizacji ....................................... 283 Kontrola dostępu w MySQL ......................................................................................... 286 Nadawanie uprawnień za pomocą polecenia GRANT ......................................... 287 Odbieranie uprawnień przy użyciu polecenia REVOKE ..................................... 289 Porady na temat kontroli dostępu ......................................................................... 290 Problem braku dostępu ........................................................................................ 292 Sprawdzanie i naprawianie plików danych MySQL ..................................................... 293 Lepiej się ubezpieczać, niż potem żałować .................................................................. 295
Rozdział 11. Zaawansowane zapytania SQL ...................................................... 297 Sortowanie wyników zapytania SELECT .................................................................... 297 Ustawianie limitów dla zapytań .................................................................................... 299 Blokowanie tabel .......................................................................................................... 300 Aliasy nazw kolumn i tabel .......................................................................................... 302 Grupowanie wyników zapytania SELECT ................................................................... 305 Złączenie lewostronne .................................................................................................. 306 Ograniczanie wyników za pomocą klauzuli HAVING ................................................. 309 Dalsze lektury ............................................................................................................... 310
Rozdział 12. Dane binarne ................................................................................ 313 Częściowo dynamiczne strony WWW ......................................................................... 313 Obsługa ładowania plików ........................................................................................... 319 Przypisywanie plikom niepowtarzalnych nazw ................................................... 322 Rejestrowanie w bazie danych ładowanych plików ...................................................... 324 Binarne typy kolumn ........................................................................................... 325 Zapisywanie plików ............................................................................................. 327 Przeglądanie zapisanych plików .......................................................................... 328 Kompletny skrypt ......................................................................................................... 332 Problemy związane z wielkimi plikami ........................................................................ 338 Rozmiar pakietów MySQL .................................................................................. 338 Ograniczenia czasu działania skryptów PHP ....................................................... 338 Zakończenie .................................................................................................................. 339
Dodatek A Składnia MySQL ........................................................................... 341 Instrukcje języka SQL obsługiwane przez MySQL ...................................................... 342 ALTER TABLE ................................................................................................... 342 ANALYZE TABLE ............................................................................................. 344 CREATE DATABASE ........................................................................................ 344 CREATE INDEX ................................................................................................ 345
8
PHP i MySQL. Witryna WWW oparta na bazie danych CREATE TABLE ................................................................................................ 345 DELETE .............................................................................................................. 347 DESCRIBE/DESC ............................................................................................... 348 DROP DATABASE ............................................................................................ 348 DROP INDEX ..................................................................................................... 348 DROP TABLE ..................................................................................................... 348 EXPLAIN ............................................................................................................ 348 GRANT ............................................................................................................... 349 INSERT ............................................................................................................... 349 LOAD DATA INFILE ......................................................................................... 350 LOCK/UNLOCK TABLES ................................................................................. 351 OPTIMIZE TABLE ............................................................................................. 352 RENAME TABLE ............................................................................................... 352 REPLACE ........................................................................................................... 353 REVOKE ............................................................................................................. 353 SELECT ............................................................................................................... 353 SET ...................................................................................................................... 359 SHOW ................................................................................................................. 359 TRUNCATE ........................................................................................................ 360 UNLOCK TABLES ............................................................................................. 361 UPDATE ............................................................................................................. 361 USE ...................................................................................................................... 362
Dodatek B Funkcje MySQL ............................................................................ 363 Funkcje przepływu sterowania ..................................................................................... 363 Funkcje matematyczne ................................................................................................. 364 Funkcje tekstowe .......................................................................................................... 366 Funkcje daty i czasu ..................................................................................................... 370 Pozostałe funkcje .......................................................................................................... 374 Funkcje używane w klauzulach GROUP BY ............................................................... 378
Dodatek C Typy danych dla kolumn tabel MySQL ........................................... 379 Typy liczbowe .............................................................................................................. 380 Typy znakowe .............................................................................................................. 383 Typy daty i czasu .......................................................................................................... 387
Dodatek D Funkcje PHP współpracujące z MySQL .......................................... 389 Najczęściej używane funkcje mysqli_* w języku PHP ................................................ 389 mysqli_affected_rows .......................................................................................... 390 mysqli_character_set_name ................................................................................. 390 mysqli_close ........................................................................................................ 390 mysqli_connect .................................................................................................... 390 mysqli_connect_errno .......................................................................................... 391 mysqli_connect_error .......................................................................................... 391 mysqli_data_seek ................................................................................................. 391 mysqli_errno ........................................................................................................ 392 mysqli_error ......................................................................................................... 392 mysqli_fetch_all .................................................................................................. 392 mysqli_fetch_array .............................................................................................. 393 mysqli_fetch_assoc .............................................................................................. 393 mysqli_fetch_field ............................................................................................... 393 mysqli_fetch_field_direct .................................................................................... 393 mysqli_fetch_fields .............................................................................................. 394
Spis treści
9 mysqli_fetch_lengths ........................................................................................... 394 mysqli_fetch_object ............................................................................................. 394 mysqli_fetch_row ................................................................................................ 395 mysqli_field_count .............................................................................................. 395 mysqli_field_seek ................................................................................................ 395 mysqli_field_tell .................................................................................................. 395 mysqli_free_result ............................................................................................... 395 mysqli_get_client_info ........................................................................................ 395 mysqli_get_client_version ................................................................................... 396 mysqli_get_host_info ........................................................................................... 396 mysqli_get_proto_info ......................................................................................... 396 mysqli_get_server_info ........................................................................................ 396 mysqli_get_server_version .................................................................................. 396 mysqli_info .......................................................................................................... 396 mysqli_insert_id .................................................................................................. 397 mysqli_num_fields ............................................................................................... 397 mysqli_num_rows ................................................................................................ 397 mysqli_ping ......................................................................................................... 397 mysqli_query ....................................................................................................... 397 mysqli_real_escape_string ................................................................................... 398 mysqli_real_query ............................................................................................... 398 mysqli_select_db ................................................................................................. 398 mysqli_set_charset ............................................................................................... 398 mysqli_stat ........................................................................................................... 399 mysqli_store_result .............................................................................................. 399 mysqli_thread_id ................................................................................................. 399 mysqli_use_result ................................................................................................ 399
Skorowidz .................................................................................... 401
10
PHP i MySQL. Witryna WWW oparta na bazie danych
Przedmowa PHP i MySQL się zmieniły. W roku 2001, gdy pisałem pierwsze wydanie tej książki, czytelnicy byli mile zaskoczeni faktem, że można stworzyć witrynę internetową złożoną z wielu stron WWW bez konieczności pisania kodu HTML oddzielnie dla każdej z tych stron. PHP wyróżniał się spośród innych języków programowania głównie tym, że można go było pobierać i instalować za darmo, a jego opanowanie nie sprawiało większych trudności. Również baza danych MySQL stanowiła proste i darmowe narzędzie służące do pokonywania trudności, jakie wcześniej mogły być rozwiązywane jedynie przez doświadczonych programistów, których pracodawcy dysponowali znacznymi środkami finansowymi. W tamtych czasach PHP i MySQL były czymś wyjątkowym, żeby nie rzec — magicznym! Jednak z biegiem lat wyrosła im dość liczna, dynamiczna konkurencja. W świecie, w którym każdy właściciel darmowego konta WordPress może w 30 sekund utworzyć pełnowymiarowy blog, żaden język programowania, choćby taki jak PHP, nie jest łatwy do nauczenia się. Również fakt, że baza danych MySQL jest darmowa, nie jest już tak pociągający. Nietrudno się domyślić, że ambicje każdego, kto rozpoczyna lekturę tej książki, wykraczają znacznie poza tworzenie rozwiązań przy użyciu darmowych narzędzi bazujących na przeciąganiu i upuszczaniu elementów myszą. Być może celem jest wręcz samodzielne opracowanie takiego nowego, atrakcyjnego narzędzia. Wszak WordPress został zaimplementowany w PHP i MySQL, dlaczego więc nie wymyślić czegoś jeszcze lepszego? Aby dotrzymać kroku konkurencji i spełnić potrzeby bardziej zaawansowanych projektów, PHP i MySQL musiały się rozwijać. Aktualnie PHP jest o wiele bardziej zawiły, niż był jeszcze w roku 2001. MySQL z kolei przekształciła się w tym czasie w o wiele bardziej złożoną i rozbudowaną bazę danych. Znajomość PHP i MySQL daje dziś zdecydowanie szersze możliwości, które w roku 2001 nie były dostępne nawet dla ekspertów w tej dziedzinie.
12
PHP i MySQL. Witryna WWW oparta na bazie danych
To była dobra wiadomość. Zła wiadomość jest natomiast taka, że — podobnie jak noża do krojenia chleba używa się o wiele łatwiej niż szwajcarskiego scyzoryka (no i trudniej się nim skaleczyć) — tak obecność wszystkich usprawnień i rozszerzeń w PHP i MySQL doprowadziła do tego, że narzędzia te zdecydowanie trudniej opanować, zwłaszcza gdy jest się ich początkującym użytkownikiem. Co gorsza, w PHP zrezygnowano z kilku rozwiązań przyjaznych dla początkujących programistów, które w roku 2001 stanowiły o sile tego języka. Z biegiem czasu okazało się bowiem, że rozwiązania te okazały się być zbyt daleko idącymi uproszczeniami, a w skrajnych przypadkach mniej doświadczeni użytkownicy korzystali z nich w nieprawidłowy sposób, przez co tworzone witryny internetowe zawierały luki bezpieczeństwa. Z takimi właśnie problemami muszą zmagać się autorzy książek dotyczących PHP i MySQL, a przeznaczonych dla początkujących czytelników. PHP i MySQL zmieniły się, a zmiany, które w nich zaszły, mocno utrudniły napisanie tej książki, ale też uczyniły ją znacznie poważniejszą. Wszak im bardziej kręta ścieżka, tym bardziej potrzebna jest mapa, prawda? W tej książce prezentuję praktyczny instruktaż, jak przy użyciu PHP i MySQL przygotować witrynę WWW opartą na bazie danych. Jeśli wasz serwer WWW zapewnia możliwości korzystania z języka PHP i baz MySQL, będziecie mogli natychmiast wprowadzić prezentowane tu rozwiązania. Jeśli nie, podam sposób instalacji obu narzędzi w systemach Windows, Mac OS X i Linux. Książka pełni rolę mapy prezentującej krętą ścieżkę, którą musi kroczyć każdy początkujący programista, aby nauczyć się współczesnych PHP i MySQL. Warto więc chwycić w garść swój ulubiony kij i ruszyć na wędrówkę!
Dla kogo przeznaczona jest ta książka? Po książkę powinni sięgnąć średnio i bardziej zaawansowani projektanci stron WWW, pragnący zapoznać się z metodami programowania po stronie serwera. Zakładam, że czytelnicy znają dobrze podstawy języka HTML, ponieważ w toku wywodów będą wielokrotnie wykorzystywane fragmenty kodu HTML, przedstawione bez wyjaśnień dotyczących ich stosowania. Nie jest natomiast konieczna żadna wiedza na temat kaskadowych arkuszy stylów (ang. Cascade Style Sheets — CSS) ani języka JavaScript; niemniej osobom, które znają ten język, będzie znacznie łatwiej zrozumieć PHP, gdyż oba języki skryptowe są bardzo podobne. Zakładam, że po przeczytaniu tej książki czytelnik przyswoi sobie wiedzę niezbędną do skonfigurowania i budowy własnej witryny WWW opartej na bazie danych. Ponadto analizując przykłady prezentowane w książce, można poznać PHP (język skryptowy działający po stronie serwera, który pozwala na bezproblemowe sięganie do bazy danych oraz zapewnia wiele innych ciekawych możliwości) oraz SQL (strukturalny język zapytań — standardowy język wykorzystywany w komunikacji z relacyjnymi bazami danych)
Przedmowa
13
w takim zakresie, w jakim są one obsługiwane przez system MySQL, obecnie najpopularniejszy spośród darmowych systemów obsługi baz danych. Jednym słowem zostanie przedstawione wszystko, co jest niezbędne do rozpoczęcia budowy własnej witryny WWW opartej na bazie danych!
Co znajdziecie w tej książce? Prezentowana książka składa się z 12 rozdziałów. Jeśli zależy wam na dogłębnym zrozumieniu tematu, należy je czytać w takiej kolejności, w jakiej zostały uporządkowane, od początku do końca. Można też przeglądać książkę pobieżnie, jeśli zamierzacie tylko odświeżyć wiadomości.
Rozdział 1. Instalacja Zanim zaczniecie budować własną witrynę WWW opartą na bazie danych, należy najpierw upewnić się, że posiadacie wszystkie narzędzia niezbędne do realizacji tego zadania. Dzięki lekturze pierwszego rozdziału dowiecie się, gdzie można zdobyć niezbędne komponenty: język skryptowy PHP oraz system zarządzania bazami danych MySQL. Zapoznacie się następnie ze sposobem ich instalacji w systemach Windows, Linux i Mac OS X. Dowiecie się także, jak sprawdzić, czy język PHP działa na serwerze WWW.
Rozdział 2. Wprowadzenie do systemu MySQL Czytelnicy chcieliby zapewne jak najszybciej przystąpić do tworzenia własnych dynamicznych stron WWW, lecz mimo to zacznę od przedstawienia ogólnego wprowadzenia do baz danych, a w szczególności do systemu zarządzania relacyjnymi bazami danych MySQL. Ci, którzy nie mieli jeszcze dotąd okazji pracować z bazami danych, niewątpliwie uznają informacje zawarte w tym rozdziale za cenne i inspirujące do dalszej lektury! Zbudujemy w nim prostą przykładową bazę danych, z której będziemy korzystać w następnych rozdziałach.
Rozdział 3. Wprowadzenie do języka PHP W rozdziale trzecim przystąpię do omówienia naprawdę ciekawych rzeczy. Wprowadzę czytelnika w sekrety języka skryptowego PHP, który bez trudu można wykorzystać do budowy stron WWW prezentujących odwiedzającym najświeższe informacje. Czytelnikom, którzy mają już pewne doświadczenie w programowaniu, wystarczy zapewne tylko pobieżne przekartkowanie tego rozdziału, ponieważ wyjaśniam w nim od podstaw zasady programowania w PHP, które są podobne do zasad w innych językach programowania. Dla początkujących rozdział ten będzie lekturą obowiązkową, ponieważ dalszy wykład opiera się w znacznej mierze na założeniu, że czytelnik posiada już prezentowaną tu wiedzę.
14
PHP i MySQL. Witryna WWW oparta na bazie danych
Rozdział 4. Publikowanie w sieci WWW danych przechowywanych w bazie MySQL W tym rozdziale połączymy ze sobą, omawiane osobno w poprzednich dwóch rozdziałach, język PHP i system MySQL, by za ich pomocą przygotować pierwsze strony WWW oparte na bazie danych. Zostaną omówione podstawowe techniki pobierania informacji z bazy danych i wyświetlania ich w czasie rzeczywistym przy użyciu języka PHP. Pokażę również, jak — korzystając z języka PHP — przygotować na stronach WWW formularze, które pozwolą użytkownikom na bieżąco wprowadzać i zmieniać informacje przechowywane w bazie danych zbudowanej na systemie MySQL.
Rozdział 5. Projektowanie relacyjnych baz danych Mimo że w poprzednich rozdziałach została już przedstawiona prosta baza danych, większość witryn WWW opartych na bazach danych wymaga o wiele bardziej złożonych systemów danych niż omówione do tej pory. Błędy popełniane na samym starcie podczas projektowania struktury bazy danych sprawiają, że budowę licznych baz danych projektów witryn WWW trzeba zarzucić lub zaczynać od początku. Dlatego też w rozdziale piątym postaram się nauczyć czytelnika zasad dobrego projektowania baz danych, kładąc w szczególności nacisk na normalizowanie danych. Jeśli nie wiecie, co ten termin oznacza, koniecznie musicie przeczytać ten rozdział!
Rozdział 6. Programowanie strukturalne w języku PHP Techniki strukturalizacji kodu PHP przydadzą się wszędzie, poza najprostszymi projektami przygotowanymi w języku PHP, w których można się bez nich obyć. Język PHP oferuje wiele funkcji ułatwiających takie organizowanie kodu. W tym rozdziale opiszę najprostsze techniki usprawniające organizowanie kodu skryptów i zarządzanie nim. Przedstawię sposób takiego korzystania z załączanych plików, by unikać konieczności wpisywania tego samego kodu po raz kolejny na różnych stronach witryny. Pokażę, jak pisać własne funkcje, rozszerzając w ten sposób możliwości języka PHP, i jak poprawiać kod tworzący skrypty.
Rozdział 7. System zarządzania zawartością Lektura rozdziału siódmego, najważniejszego w książce, okaże się zbawienna dla wszystkich sfrustrowanych twórców stron WWW, którzy do tej pory musieli dokonywać poprawek w setkach osobnych stron WWW, by zmienić projekt witryny. Zaprezentuję kod przykładowego systemu zarządzania zawartością, zaprojektowany dla prostej bazy przechowującej teksty dowcipów, informacje o ich autorach i podział na kategorie. Podobny system będziecie mogli wykorzystać do zarządzania zawartością w waszych witrynach. Wystarczy kilka prostych modyfikacji i uzyskamy system administrowania witryną WWW, pozwalający autorom tekstów publikować materiały w witrynie natychmiast, bez konieczności posiadania nawet podstawowej wiedzy na temat języka HTML!
Przedmowa
15
Rozdział 8. Formatowanie zawartości przy użyciu wyrażeń regularnych Gdy implementuje się przyjazne, łatwe w obsłudze narzędzie, które służy do dodawania nowych treści na stronach internetowych i jest przeznaczone dla administratorów nieznających języka HTML, nie oznacza to wcale, że treści te muszą mieć wyłącznie postać zwykłego tekstu. W rzeczywistości treści takie można dodatkowo na różne sposoby formatować. W tym rozdziale zdradzę kilka zręcznych sztuczek związanych z formatowaniem tekstu na stronach WWW wyświetlających zawartość naszej bazy danych — sztuczek, które pozwolą między innymi na wprowadzenie prostego formatowania takiego tekstu jak wytłuszczanie czy kursywa.
Rozdział 9. Obsługa cookies i sesji oraz kontrola dostępu Czym są sesje? I jak się one mają do cookies, tej od dawna wykorzystywanej w sieci WWW techniki przechowywania trwałych danych na temat użytkownika? Dlaczego trwałe przechowywanie danych odgrywa taką rolę we współczesnych systemach handlu elektronicznego i innych aplikacjach WWW? W tym rozdziale postaram się odpowiedzieć na wymienione tu pytania, wyjaśniając, w jaki sposób język PHP obsługuje cookies i sesje oraz jak funkcjonują te dwa narzędzia. Na koniec rozdziału wszystkie opisane mechanizmy zostaną wykorzystane, aby zaimplementować prosty koszyk na zakupy wraz z systemem kontroli dostępu.
Rozdział 10. Administrowanie bazą MySQL Mimo że system MySQL należy do najprostszych systemów relacyjnych baz danych i jest zarazem odpowiedni dla użytkowników, którzy nie potrzebują bardziej wyszukanych funkcji baz danych, warto zapoznać się z zastrzeżeniami związanymi z przechowywaniem w nim zawartości naszej witryny WWW. W tym rozdziale pokażę między innymi, jak wykonywać rezerwowe kopie danych i zarządzać dostępem do bazy MySQL. Oprócz tego ujawnię kilka użytecznych trików dla wtajemniczonych (na przykład co zrobić, jeśli zapomnieliśmy swojego hasła w systemie MySQL). Przedstawię również sposób naprawy bazy danych, która została uszkodzona w wyniku awarii serwera.
Rozdział 11. Zaawansowane zapytania SQL W rozdziale piątym, „Projektowanie relacyjnych baz danych”, była mowa o problemach związanych z modelowaniem złożonych relacji między elementami informacji przechowywanymi w relacyjnej bazie danych, takiej jak MySQL. W teorii rzecz wygląda w miarę prosto, lecz aby przełożyć te idee na rozwiązania praktyczne, konieczne jest poznanie kilku dodatkowych trików związanych z językiem SQL. W tym rozdziale omówię kilka zaawansowanych możliwości tego języka, byście potrafili operować nim jak prawdziwi profesjonaliści.
Rozdział 12. Dane binarne Niektóre z ciekawszych możliwości, które oferuje projekt witryny oparty na bazie danych, związane są z manipulowaniem plikami binarnymi. Dobrym tego przykładem są usługi umożliwiające składowanie plików w sieci. Niemniej jednak, wykonując czynność nawet tak prostą jak tworzenie osobistej galerii zdjęć w Internecie, można znacznie
16
PHP i MySQL. Witryna WWW oparta na bazie danych
skorzystać dzięki możliwości przechowywania plików binarnych (zdjęć) w bazie danych, z której będą w razie potrzeby szybko pobierane. W tym rozdziale pokażę, jak przyśpieszyć wyświetlanie witryny WWW, tworząc w regularnych odstępach czasu statyczne kopie normalnie budowanych dynamicznie stron WWW — oczywiście za pomocą języka PHP! Uzbrojeni w te podstawowe techniki żonglowania plikami przygotujemy prosty system składowania i przechowywania plików binarnych w Internecie. Na koniec wreszcie omówię zalety i wady pracy z danymi binarnymi w systemie MySQL.
Konwencje użyte w książce W trakcie lektury od razu da się zauważyć, że niektóre informacje zostały specjalnie wyróżnione odrębnymi czcionkami i stylami. Opisano je w poniższych punktach.
Przykładowe kody źródłowe Kod źródłowy jest prezentowany w książce przy użyciu czcionki o stałej szerokości znaków: Piękny letni dzień
To był idealny dzień na spacer po parku. Ptaki śpiewały, a wszystkie dzieci były jeszcze w szkole.
Jeżeli prezentowany kod źródłowy znajduje się w jednym z plików dołączonych do tej książki, wówczas na początku listingu programu wskazana zostanie nazwa tego pliku: Listing 0.1. przykład.css .footer { background-color: #CCC; border-top: 1px solid #333; }
Jeżeli prezentowany jest tylko fragment kodu źródłowego, obok nazwy pliku źródłowego znajduje się słowo fragment: Listing 0.2. przykład.css (fragment) border-top: 1px solid #333;
Jeżeli do istniejącego przykładowego kodu źródłowego należy dopisać jakiś fragment, nowy kod źródłowy jest prezentowany przy użyciu czcionki pogrubionej: function animuj() { nowa_zmienna = "Witaj"; }
Przedmowa
17
Jeżeli ponadto fragment już istniejącego kodu jest przywoływany w jakimś kontekście z pominięciem całości kodu źródłowego, wyświetlony zostanie pionowy wielokropek: function animuj() { . . . return nowa_zmienna; }
Porady, uwagi i ostrzeżenia Hej, kolego! Wskazówki to przydatne, dodatkowe porady.
Halo, przepraszam… Uwagi to użyteczne informacje dodatkowe. Są związane z omawianym zagadnieniem, lecz nie mają dla niego kluczowego znaczenia. Można je traktować jak warte zapamiętania dodatkowe wiadomości.
Pamiętaj, aby zawsze… … poświęcić tym fragmentom książki szczególną uwagę.
Uważaj! Ostrzeżenia traktują o wszelkich okolicznościach, które mogą wyprowadzić w pole nieuważnego programistę.
18
PHP i MySQL. Witryna WWW oparta na bazie danych
Rozdział 1.
Instalacja Zamiarem autora niniejszej książki jest pokazanie, w jaki sposób wyjść poza proste projektowanie statycznych stron WWW po stronie klienta, oparte na czystym kodzie HTML. Poznamy świat witryn internetowych opartych na bazach danych, a także pochylimy się nad szerokim spektrum dynamicznych narzędzi i rozwiązań oraz możliwości, które się dzięki nim otwierają. Można więc już zacząć się cieszyć, bo wspomnianym zagadnieniom poświęcona jest cała ta książka! Zanim utworzymy pierwszą dynamiczną witrynę WWW, konieczne będzie zainstalowanie niezbędnych narzędzi. W tym rozdziale pokażę, jak ściągnąć i zainstalować dwa pakiety oprogramowania, których będziemy potrzebować. Domyślasz się już, co to za oprogramowanie? Dla ułatwienia dodam, że ich nazwy występują już w tytule książki! Są to — oczywiście — system zarządzania bazami danych MySQL i język PHP. Jeżeli tworzyłeś już wcześniej witryny internetowe przy użyciu języka HTML, arkuszy stylów CSS, a nawet kodu JavaScript, ładowanie na zdalny serwer plików tworzących tę witrynę nie będzie niczym nowym. Być może serwer ten należy do dostawcy usług internetowych, za które płacisz. Może jest to darmowa usługa świadczona przez ISP (ang. Internet Service Provider) albo serwer WWW skonfigurowany i utrzymywany przez dział informatyki firmy, w której pracujesz. Bez względu jednak na okoliczności, po załadowaniu plików na komputer docelowy specjalny program, tak zwany serwer WWW (ang. web server), będzie mógł je odnaleźć i udostępniać ich kopie każdej przeglądarce, takiej jak Internet Explorer czy Firefox, która te pliki wywoła. Najpopularniejszymi serwerami WWW, o których słyszała zapewne większość czytelników, są Apache oraz Internet Information Services (IIS). PHP to język skryptowy działający po stronie serwera. Można traktować go jak „dodatek” (ang. plugin) do serwera WWW, który pozwala w odpowiedzi na żądanie przeglądarki internetowej zwracać coś więcej, a nie tylko wierne kopie plików. Po zainstalowaniu języka PHP nasz serwer WWW będzie uruchamiał małe programy (zwane skryptami PHP), co zapewni wspaniałe możliwości, takie jak pobieranie najświeższych informacji z bazy danych i wstawianie ich „w locie” na stronę WWW przed wysłaniem jej do przeglądarki użytkownika. Wspomniane zadania będą tematem niemal całej książki. A co najważniejsze, z języka PHP po ściągnięciu oprogramowania z sieci można korzystać zupełnie za darmo.
20
PHP i MySQL. Witryna WWW oparta na bazie danych
Aby skrypty PHP mogły pobierać informacje z bazy danych, trzeba mieć w ogóle jakąś bazę danych. W tym miejscu właśnie należy wspomnieć o MySQL. Jak wiadomo, MySQL to system zarządzania relacyjnymi bazami danych (w skrócie RDBMS, od angielskich słów: relational database management system). Tym, jak on działa i jaką funkcję pełnić będzie w konstrukcji witryny, zajmiemy się później, na razie jednak powinna wystarczyć nam wiedza, że zasadniczo jest to pakiet oprogramowania służący do organizowania dużych zasobów informacji i wydajnego zarządzania nimi przy jednoczesnym utrzymywaniu prawidłowych relacji między tymi informacjami. System RDBMS MySQL ma również tę zaletę, że pozwala na bardzo łatwe sięganie do przechowywanych w jego bazach informacji za pomocą języków skryptowych działających po stronie serwera, takich jak PHP. Podobnie jak PHP, MySQL można używać za darmo w większości zastosowań. Celem tego rozdziału jest zainstalowanie i uruchomienie serwera WWW wyposażonego w język PHP i serwer baz danych MySQL. Przedstawię krok po kroku czynności, jakie należy wykonać na komputerach z systemem operacyjnym Windows, Mac OS X oraz Linux. Dlatego, bez względu na to, w jakim środowisku pracujesz, powinieneś w tym rozdziale znaleźć przydatne dla siebie informacje.
Własny serwer WWW Przy odrobinie szczęścia może się okazać, że na serwerze WWW, na którym działa nasza witryna, jest już zainstalowany system MySQL i język PHP. I tak rzeczywiście jest w znakomitej większości przypadków — to jeden z powodów, dla których PHP i MySQL są tak popularne. Jeżeli serwer WWW dla naszej witryny posiada wspomniane narzędzia, mam dobrą wiadomość: będziesz mógł udostępnić swoją pierwszą witrynę opartą na bazie danych bez konieczności wykupywania odpowiedniej usługi u dostawcy usług internetowych. Zła wiadomość jest zaś taka, że i tak konieczne będzie samodzielne zainstalowanie PHP i MySQL, aby uruchomić własny serwer WWW z tymi narzędziami i testować witrynę internetową przed jej opublikowaniem na serwerze ogólnie dostępnym w Internecie. Gdy tworzy się statyczne witryny internetowe, zwykle wystarczy załadować pliki HTML na serwer bezpośrednio z własnego komputera i od razu sprawdzić w przeglądarce, czy są prawidłowe. Do wyświetlenia plików HTML nie potrzeba dodatkowego oprogramowania w postaci serwera WWW, ponieważ przeglądarki same interpretują kod HTML. Gdy jednak przychodzi do wywołania dynamicznej witryny WWW utworzonej w PHP i MySQL, przeglądarki sobie nie radzą! Nie „rozumieją” skryptów PHP, ponieważ skrypty te zawierają kod języka przeznaczony dla serwera WWW współpracującego z interpreterem PHP. Dopiero tak wyposażony serwer WWW może wykonać kod i na jego podstawie wygenerować kod HTML zrozumiały dla przeglądarek. Dlatego oprócz publicznie dostępnego serwera internetowego trzeba również posiadać własny serwer WWW, aby na nim rozwijać witrynę internetową.
Rozdział 1. ♦ Instalacja
21
Jeśli pracujesz w firmie, w której funkcjonuje dział informatyki, może jest już gdzieś dostępny serwer WWW przeznaczony do budowania witryn internetowych. Zwykle pliki tworzące witrynę utrzymuje się i rozwija na dysku sieciowym, pełniącym rolę wewnętrznego serwera WWW przeznaczonego właśnie do prac rozwojowych. Gdy witryna jest już w takim stanie, że można ją udostępnić wszem i wobec, pliki kopiuje się z dysku sieciowego na publiczny serwer WWW. Jeżeli jesteś szczęśliwcem, który ma dostęp do takiego środowiska, czytanie tego rozdziału w całości nie jest konieczne. Jednak konieczne będzie uzyskanie od administratora zarządzającego serwerem rozwojowym tych samych informacji, o których piszę w punkcie „O co zapytać dostawcę usług internetowych?”. Zawsze bowiem, gdy zaczyna się pracę z PHP i MySQL, trzeba dysponować pewnymi niezbędnymi informacjami.
Instalacja w systemie Windows W tym podrozdziale pokażę, jak uruchamia się PHP i MySQL na serwerze działającym na komputerze z systemem operacyjnym Windows XP, Windows Vista lub Windows 7. Jeżeli używasz systemu operacyjnego innego niż wymienione, możesz ten podrozdział w całości pominąć.
Jednoczesna instalacja wszystkich komponentów Zwykle zalecam, aby serwer WWW, PHP oraz MySQL instalować i konfigurować oddzielnie, każdy z oficjalnego, odrębnego pakietu instalacyjnego. Jest to podejście szczególnie przydatne dla użytkowników początkujących, ponieważ dzięki temu łatwiej zrozumieć zależności między poszczególnymi komponentami. Jeśli jednak nie masz czasu na instalowanie oddzielnie poszczególnych elementów albo chcesz na dzień lub dwa utworzyć tymczasowe środowisko rozwojowe, zapewne wygodniejsze będzie opisywane w tym punkcie rozwiązanie minimalistyczne. Jeżeli jesteś gotów na to, by poświęcić nieco więcej czasu i zainstalować poszczególne komponenty oddzielnie, możesz przejść od razu do punktu „Instalacja poszczególnych komponentów”. Pakiet WampServer (słowo Wamp to skrót od nazw Windows, Apache, MySQL i PHP) jest darmowym, zbiorczym programem, który zawiera wbudowane kopie najnowszych wersji serwera WWW Apache, języka PHP oraz serwera baz danych MySQL. Spójrzmy, jak przebiega proces instalacji przy użyciu pakietu WampServer. 1. Pobierz najnowszą wersję pakietu z witryny WampServer1. Po pobraniu pliku
(w czasie pisania tej książki WampServer 2.0g miał około 16 MB), trzeba go dwukrotnie kliknąć myszą, aby rozpocząć działanie programu instalacyjnego, jak na rysunku 1.1. 1
http://www.wampserver.com/en/
22
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 1.1. Instalator pakietu WampServer
2. Program instalacyjny poprosi o podanie docelowej lokalizacji dla pakietu
WampServer. Domyślna lokalizacja c:\wamp, widoczna na rysunku 1.2, jest w większości przypadków najlepszym wyborem. Jeśli jednak masz inne preferencje dotyczące katalogu, w którym pakiet powinien zostać zainstalowany, możesz tę instalację zmienić. Rysunek 1.2. Najlepiej wybrać domyślny katalog instalacyjny 3. Pod koniec procesu instalacji WampServer poprosi o wskazanie domyślnej
przeglądarki internetowej. Wskazana przeglądarka będzie uruchamiana zawsze, gdy kliknięta zostanie dołączona do pakietu ikona narzędzia dostępna w pasku narzędzi systemowych. Jeżeli na komputerze zainstalowana jest przeglądarka Firefox, WampServer zapyta, czy ma ona zostać potraktowana jak przeglądarka domyślna. Jeżeli wybierzesz odpowiedź No albo masz zainstalowaną inną przeglądarkę, program instalacyjny poprosi o wskazanie pliku wykonywalnego przeglądarki, której używasz. Na rysunku 1.3 wskazano plik wykonywalny explorer.exe przeglądarki Internet Explorer. Jeżeli używasz jeszcze innej przeglądarki, na przykład Safari albo Opera, trzeba będzie odnaleźć jej plik wykonywalny i wskazać go programowi instalacyjnemu. 4. W trakcie instalacji WampServer uruchomi wbudowaną kopię serwera Apache
HTTP Server — serwera WWW najczęściej używanego do tworzenia witryn w języku PHP. W tym momencie system Windows prawdopodobnie wyświetli alert zabezpieczeń, widoczny na rysunku 1.4 i wywołany faktem, że serwer WWW rozpocznie nasłuchiwanie żądań przeglądarek z zewnątrz. Aby zyskać całkowitą pewność, że Apache będzie odrzucać połączenia z zewnątrz i umożliwić przeglądanie stron dostępnych na serwerze rozwojowym wyłącznie przeglądarce internetowej zainstalowanej na komputerze lokalnym, należy kliknąć przycisk Blokuj nadal. WampServer posiada jednak własną
Rozdział 1. ♦ Instalacja
23
Rysunek 1.3. Domyślnie wybrany jest plik wykonywalny przeglądarki Internet Explorer
Rysunek 1.4. Alert zabezpieczeń to jednocześnie informacja, że Apache zaczął działać
wbudowaną możliwość zablokowania połączeń z zewnątrz, dlatego proponuję kliknąć przycisk Odblokuj, aby zapewnić sobie możliwość sterowania widocznością serwera rozwojowego zależnie od bieżących potrzeb. 5. W kolejnym kroku, widocznym na rysunku 1.5, program instalacyjny pakietu
WampServer poprosi o wskazanie adresu serwera SMTP oraz adresu poczty elektronicznej. Skrypt PHP może wysyłać wiadomości pocztowe, a informacje podane na tym etapie procesu instalacji zostaną wykorzystane do odnalezienia serwera poczty wychodzącej oraz podania adresu nadawcy wiadomości pocztowej. Należy zatem wpisać adres poczty elektronicznej, a jeżeli pamiętasz adres używanego przez siebie serwera SMTP, również warto go podać. Tymczasowo można także pozostawić wartości domyślne i zdefiniować je później ręcznie, gdy trzeba będzie wysłać pocztę elektroniczną przez skrypt PHP. Gdy proces instalacji dobiegnie końca, można uruchomić WampServer. Jego ikona będzie dostępna na pasku narzędzi systemowych. Wystarczy ją kliknąć, aby wywołać menu pakietu WampServer widoczne na rysunku 1.6. Domyślnie serwer jest dostępny wyłącznie dla przeglądarek internetowych działających lokalnie na komputerze. Gdy w menu wybrane zostanie polecenie Put Online, serwer stanie się widoczny i dostępny również na zewnątrz.
24
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 1.5. Należy podać adres serwera SMTP, jeżeli się go zna
Rysunek 1.6. Menu pakietu WampServer
Aby sprawdzić, czy WampServer działa prawidłowo, należy wybrać polecenie Localhost znajdujące się u góry menu. W odpowiedzi w przeglądarce internetowej otwarta zostanie strona główna serwera, widoczna na rysunku 1.7. Rysunek 1.7. Na stronie głównej serwera WampServer znajduje się potwierdzenie, że Apache, PHP i MySQL zostały zainstalowane
Rozdział 1. ♦ Instalacja
25
Po zakończeniu pracy z serwerem WampServer można go wyłączyć (wraz ze wszystkimi serwerami wbudowanymi) przez kliknięcie prawym przyciskiem myszy ikony pakietu w pasku narzędzi systemowych i wybranie polecenia Exit. Gdy natomiast znów będzie trzeba uruchomić witrynę opartą na bazie danych, wystarczy WampServer ponownie włączyć! Dalej w książce będziemy korzystać z niektórych programów udostępnianych w pakiecie WampServer. Aby zapewnić sobie ich prawidłowe działanie, programy te należy dopisać do ścieżki systemowej Windows. Aby do ścieżki systemowej Windows dodać programy wykonujące polecenia serwera baz danych MySQL zainstalowanego w ramach WampServer, należy wykonać następujące instrukcje. 1. Otwórz Panel sterowania sytemu Windows. Znajdź i dwukrotnie kliknij myszą
ikonę System. 2. Wykonaj czynność odpowiednią dla używanej wersji systemu Windows, czyli: w systemie Windows XP przejdź do zakładki Zaawansowane okna
Właściwości systemu, w systemie Windows Vista lub Windows 7 kliknij znajdujące się na bocznym
pasku łącze Zaawansowane ustawienia systemu. 3. Kliknij przycisk Zmienne środowiskowe. 4. Na liście o nazwie Zmienne użytkownika dla użytkownik sprawdź, czy istnieje zmienna o nazwie PATH. Jeżeli zmienna istnieje, wybierz ją i kliknij przycisk Edytuj. Jeżeli zmienna nie istnieje, kliknij przycisk Nowy i w polu Nazwa zmiennej wpisz nazwę PATH. 5. W polu Wartość zmiennej wpisz ścieżkę dostępu do katalogu bin2 serwera
MySQL zainstalowanego wraz z WampServer. Jeżeli pole Wartość zmiennej jest puste, wpisz ręcznie ścieżkę dostępu. Jeżeli w polu Wartość zmiennej są już jakieś dane, na końcu tej wartości wpisz znak średnika (;) i po nim dopisz ścieżkę dostępu. 6. Kliknij przycisk OK we wszystkich otwartych oknach, aby zatwierdzić dokonane
zmiany.
2
Ścieżka dostępu będzie zależeć od tego, gdzie zainstalowany został WampServer oraz od wersji serwera MySQL zawartego w pakiecie. W moim systemie operacyjnym ścieżka dostępu ma postać C:\wamp\bin\mysql\mysql5.1.34\bin. Aby sprawdzić, jaka jest dokładna ścieżka dostępu w używanym systemie operacyjnym, najlepiej użyć Eksploratora Windows i przejrzeć katalog instalacyjny serwera WampServer
Rozdział 1. ♦ Instalacja
27
1. Server Type
Przy założeniu, że serwer MySQL jest instalowany dla celów rozwojowych na używanym komputerze biurkowym, należy wybrać opcję Developer Machine. 2. Database Usage
Jeżeli nie ma wyraźnych przesłanek, że konieczne będzie korzystanie z transakcji (dla większości aplikacji PHP obsługa transakcji nie jest wymagana), najlepiej wybrać opcję Non-Transactional Database Only. 3. Connection Limit
Należy wybrać opcję Decision Support (DSS)/OLAP), aby zoptymalizować pracę serwera MySQL pod kątem umiarkowanej liczby obsługiwanych połączeń. 4. Networking Options
Trzeba usunąć zaznaczenie opcji Enable Strict Mode, aby zapewnić zgodność serwera MySQL ze starszym kodem języka PHP, który być może będzie wykorzystywany w dalszej pracy. 5. Default Character Set
Należy wybrać opcję Best Support For Multilingualism, aby wskazać serwerowi MySQL, że używany będzie tekst kodowany w standardzie UTF-8. Standard ten zapewnia obsługę pełnego zakresu znaków narodowych używanych we współczesnych witrynach internetowych. 6. Windows Options
Opcja pozwala na zainstalowanie serwera MySQL jako usługi systemu Windows uruchamianej automatycznie; warto również zaznaczyć opcję Include Bin Directory in Windows PATH, aby ułatwić sobie uruchamianie narzędzi administracyjnych MySQL z poziomu wiersza poleceń. 7. Security Options
Należy usunąć zaznaczenie opcji Modify Security Settings. Najlepiej poznać metodę definiowania hasła dla użytkownika root, o którym mowa jest na tym etapie konfiguracji, bez korzystania z pomocy kreatora, dlatego w punkcie „Zadania poinstalacyjne” opiszę, jak wykonuje się tę czynność samodzielnie.
Instalowanie języka PHP Kolejnym krokiem jest zainstalowanie języka PHP. Należy przejść do strony PHP Downloads5 i w sekcji Windows Binaries wybrać łącze PHP 5.2.x zip package. Lepiej unikać wersji samoinstalującej (installer), którą wprawdzie łatwiej się instaluje, lecz pozbawia ona użytkownika elastyczności, jaką daje instalowanie języka PHP ręcznie.
5
http://www.php.net/downloads.php
28
PHP i MySQL. Witryna WWW oparta na bazie danych
Co z PHP 4? W trakcie pisania tej książki zdecydowanie zalecaną wersją języka PHP była wersja PHP 5. Jeszcze przez kilka lat od udostępnienia pierwszej wersji PHP 5 wielu programistów nadal używało wersji PHP 4 ze względu na jej wielokrotnie udowodnioną stabilność i wydajność; nawet teraz dość często się zdarza, że dostawcy usług internetowych nie uaktualnili udostępnianych serwerów do wersji PHP 5. Trudno jednak usprawiedliwić takie zaniechanie, ponieważ PHP 5 jest o wiele lepszym językiem, a rozwój wersji PHP 4 dawno został zarzucony. Jeżeli dostawca, z którego usług korzystasz, wciąż żyje przeszłością i udostępnia PHP 4, lepiej znajdź innego!
Język PHP został zaprojektowany jako dodatek do popularnych serwerów WWW, takich jak Apache czy Internet Information Services. Dlatego przed zainstalowaniem języka PHP trzeba najpierw zainstalować na komputerze serwer WWW. Wiele wersji systemu operacyjnego Windows zawiera rozbudowany serwer WWW o nazwie Internet Information Services (IIS), jednak są pewne wyjątki od tej reguły. Pozbawione IIS są między innymi Windows XP Home, Windows Vista Home i Windows 7 Home Basic, dlatego w tych wersjach systemu trzeba samodzielnie zainstalować serwer WWW, aby w ogóle tworzyć witryny internetowe korzystające z bazy danych. Trzeba również zaznaczyć, że pozostałe odmiany systemu Windows wyposażone zostały różne wersje serwera IIS, przez co procedura ich konfiguracji i przystosowania do pracy z PHP może się różnić w wielu aspektach. Jeśli pomimo tych zastrzeżeń nadal jesteś zdecydowany, aby skorzystać z IIS, weź także pod uwagę, że udostępnianie na serwerze IIS witryn internetowych zaimplementowanych w PHP jest praktyką dość rzadko spotykaną. Generalnie tańszym i bardziej niezawodnym rozwiązaniem jest utrzymywanie witryn PHP na serwerach z systemem operacyjnym należącym do rodziny systemów Linux, z zainstalowanym darmowym serwerem WWW Apache. Chyba jedynym poważnym uzasadnieniem dla tworzenia witryn w PHP dla serwera IIS może być fakt, że firma, w której pracujesz, zainwestowała już spore środki w serwery Windows udostępniające aplikacje napisane w ASP.NET (technologii, której obsługa jest wbudowana w IIS) i z jakiegoś powodu również trzeba, by w tej samej infrastrukturze udostępnić także aplikację zaimplementowaną w PHP. Oczywiście, nie jest to wymagane, jednak najłatwiej zainstalować serwer rozwojowy w środowisku najbardziej zbliżonym do tego, w jakim utworzona witryna zostanie ostatecznie udostępniona. Z tego względu gorąco zachęcam do wykorzystania serwera Apache — nawet jeśli używany jest system operacyjny Windows. Jeżeli jednak wciąż obstajesz przy udostępnianiu aplikacji PHP na serwerze IIS (lub nalega na to przełożony), wszystkie niezbędne instrukcje znajdziesz w pliku install.txt zawartym w archiwum zip pobranym ze strony poświęconej książce. Aby zainstalować serwer Apache na komputerze, należy przejść na witrynę projektu The Apache HTTP Server Project6 i poszukać tej wersji serwera, która jest wskazana jako najlepsza spośród aktualnie dostępnych (w trakcie powstawania książki była to wersja 2.2.11, co widać na rysunku 1.9). 6
http://httpd.apache.org/
Rozdział 1. ♦ Instalacja
29
Rysunek 1.9. Oto najlepsza dostępna wersja — nie warto szukać innej!
Po przejściu do strony pobierania Download trzeba odnaleźć na niej łącza prowadzące do poszczególnych dostępnych wersji serwera. Nas interesuje wersja Win32 Binary without crypto, wskazana na rysunku 1.10. Rysunek 1.10. Wersja serwera Apache, której potrzebujemy
Gdy plik zostanie pobrany, należy tradycyjnie kliknąć go dwukrotnie myszą, aby uruchomić kreator instalacji. Po kilku krokach wyświetlony zostanie ekran Server Information. Jeżeli serwer Apache ma być dostępny w sieci WWW, opcje widoczne na tym ekranie będą istotne, natomiast dla serwera rozwojowego można je zdefiniować w dowolny sposób. Jeżeli znasz nazwę sieciową swojego komputera, wpisz ją w polu Server Name. Jeżeli, tak jak ja, przywiązujesz dużą wagę do szczegółów, możesz też wpisać własny adres poczty elektronicznej. Jeśli na tym samym komputerze działa już inny serwer WWW (na przykład wcześniej zainstalowano na tej samej maszynie serwer IIS, aby rozwijać na niej aplikacje ASP.NET), na ekranie można wybrać opcję only for the Current User, on Port 8080, when started Manually. Dzięki temu uniknie się w przyszłości konfliktów z już działającym innym serwerem WWW nasłuchującym na porcie 80. Na następnym ekranie jako Setup Type trzeba wybrać opcję Typical i kontynuować działanie kreatora, aby przeprowadzić cały proces instalacji. Po jej zakończeniu w pasku narzędzi systemu operacyjnego powinna pojawić się nowa ikona narzędzia Apache Service Monitor. Jeśli w trakcie procesu instalacji pozostałeś przy domyślnej opcji automatycznego uruchamiania serwera Apache, wskaźnik stanu serwera powinien mieć kolor zielony, jak na rysunku 1.11. W przeciwnym razie trzeba będzie samodzielnie uruchomić serwer Apache w sposób pokazany na rysunku 1.12.
Rysunek 1.11. Zielona ikona stanu wskazuje, że Apache działa
Rysunek 1.12. Aby ręcznie uruchomić serwer Apache, trzeba wybrać polecenie Start
30
PHP i MySQL. Witryna WWW oparta na bazie danych
Narzędzie Apache Service Monitor pozwala także na zatrzymanie pracy serwera Apache, gdy tylko praca nad aplikacją w danym dniu dobiegnie końca. Gdy Apache będzie już skonfigurowany i uruchomiony, należy uruchomić przeglądarkę internetową i w pasku adresu wpisać http://localhost. Jeśli w trakcie konfiguracji wybrano opcję uruchamiania serwera Apache na porcie 8080, w pasku adresu trzeba wpisać http://localhost:8080. Po naciśnięciu klawisza Enter w przeglądarce powinna pojawić się strona widoczna na rysunku 1.13, stanowiąca potwierdzenie, że Apache działa prawidłowo. Rysunek 1.13. Potwierdzenie, że Apache działa prawidłowo
Zakończenie procedury instalacji i uruchamiania serwera Apache oznacza, że możemy już przystąpić do instalacji języka PHP. W tym celu należy wykonać następujące czynności. 1. Rozpakuj plik ściągnięty z witryny PHP do wybranego katalogu. Osobiście
polecałbym katalog C:\PHP; od tego momentu tak właśnie będę oznaczał katalog instalacyjny języka PHP, lecz czytelnicy mogą, oczywiście, wybrać zupełnie inny katalog. 2. Znajdź w folderze PHP plik o nazwie php.ini-dist i skopiuj go. Najłatwiej
to zrobić przez kliknięcie pliku prawym przyciskiem myszy, przeciągnięcie go (bez zwalniania przycisku) na niewielką odległość w tym samym oknie Eksploratora Windows i wybranie w menu podręcznym polecenia Kopiuj tutaj. W ten sposób powstanie nowy plik o nazwie Kopia php.ini-dist (zależnie od używanej wersji systemu Windows). Nowy plik trzeba odszukać na liście plików i zmienić jego nazwę na php.ini. Gdy Windows zapyta, czy jesteś pewien, że chcesz zmienić rozszerzenie pliku (z .ini-dist na .ini), kliknij przycisk Tak. 3. Otwórz plik php.ini w swoim ulubionym edytorze plików tekstowych.
Jeśli nie masz ulubionego edytora, po prostu kliknij go dwukrotnie myszą, aby otworzyć go w Notatniku. Jest to bardzo duży plik, zawierający wiele tajemniczych opcji, nas jednak interesuje wiersz zaczynający się od doc_root (w jego wyszukaniu pomocne okaże się polecenie Edycja/Znajdź Notatnika). W oryginalnej postaci wiersz ten ma postać: doc_root =
Na końcu tego wiersza wpisz ścieżkę dostępu do głównego katalogu dokumentów dla serwera WWW. W przypadku serwera Apache katalogiem tym jest htdocs znajdujący się w głównym katalogu serwera. Jeżeli Apache został zainstalowany w lokalizacji domyślnej, ścieżką dostępu do głównego
Rozdział 1. ♦ Instalacja
31
System Windows domyślnie ukrywa znane sobie rozszerzenia Gdy zmienisz nazwę pliku na php.ini, może się okazać, że obok ikony jest teraz widoczna nazwa pliku w postaci php, bez rozszerzenia. Przyczyną jest fakt, że domyślnie system Windows został skonfigurowany w taki sposób, by ukrywać znane sobie rozszerzenia plików. Ponieważ Windows „wie”, że pliki z rozszerzeniem .ini to pliki ustawień konfiguracyjnych, automatycznie je ukrywa. Nietrudno sobie wyobrazić, do jakich nieporozumień funkcja ta może doprowadzić. Gdy w przyszłości zajdzie konieczność edycji pliku php.ini, warto sprawdzić wcześniej jego rozszerzenie, aby odróżnić plik konfiguracyjny od plików php.gif i php.exe znajdujących się w tym samym folderze. Aby wyłączyć opcję ukrywania rozszerzeń, trzeba otworzyć Panel sterowania systemu Windows i poszukać polecenia Opcje folderów. Później otworzyć okno Opcje folderów i przejść do zakładki Widok, po czym w sekcji Pliki i foldery usunąć zaznaczenie pola wyboru Ukryj rozszerzenia znanych typów plików, jak pokazano na rysunku 1.14. Rysunek 1.14. Warto włączyć wyświetlanie rozszerzeń dla wszystkich plików
katalogu dokumentów będzie C:\Program Files\Apache Software Foundation\Apache2.2\htdocs. Jeśli natomiast zainstalowałeś serwer w innej lokalizacji, musisz odnaleźć folder htdocs i wpisać ścieżkę dostępu do niego: doc_root = "C:\Program Files\Apache Software Foundation\Apache2.2\htdocs"
Nieco dalej w tym samym pliku znajdziesz wiersz zaczynający się od extension_dir, w którym trzeba wskazać ścieżkę do podfolderu ext w Twoim folderze PHP: extension_dir = "C:\PHP\ext"
Dalej w tymże pliku zobaczysz grupę wierszy zaczynających się od ;extension=. Definiują one dodatkowe rozszerzenia i domyślnie są wyłączone. Nam zależy na włączeniu rozszerzenia MySQL, aby język PHP mógł komunikować się z systemem MySQL. W tym celu należy usunąć znak średnika z początku wiersza rozszerzenia php_mysqli.dll, który powinien po tym zabiegu wyglądać następująco: extension=php_mysqli.dll
32
PHP i MySQL. Witryna WWW oparta na bazie danych
php_mysqli, a nie php_mysql Bezpośrednio nad wierszem dotyczącym php_mysqli.dll znajduje się wiersz z nazwą pliku php_mysql.dll. Litera i w nazwie php_mysqli oznacza angielskie słowo improved, czyli „ulepszony”. Dla naszych potrzeb trzeba włączyć nowe, ulepszone rozszerzenie dla serwera MySQL. Rozszerzenie bez litery i w nazwie jest przestarzałe i niektóre z jego funkcji są już niezgodne z aktualnie używanymi wersjami serwera MySQL.
Jeszcze niżej w pliku znajdź wiersz opcji session.save_path. Tak jak poprzednio, usuń średnik z początku wiersza, aby włączyć opcję, po czym przypisz jej ścieżkę do katalogu plików tymczasowych TEMP systemu Windows: session.save_path = "C:\WINDOWS\Temp"
Zapisz zmiany wprowadzone w pliku i zamknij edytor. W ten sposób skonfigurowaliśmy język PHP. Czas zatem na skonfigurowanie serwera Apache w taki sposób, aby wykorzystywał język PHP jako program dodatkowy. 1. Uruchom Notatnik jako administrator. Jest to niezwykle istotne, ponieważ
domyślnie plik konfiguracyjny serwera Apache jest dostępny do edycji wyłącznie dla administratora. W tym celu w menu Start znajdź ikonę Notatnika (powinna znajdować się w menu Wszystkie programy/Akcesoria) i kliknij ją prawym przyciskiem myszy, po czym wybierz polecenie Uruchom jako administrator. 2. W Notatniku wybierz polecenie Plik/Otwórz. W folderze instalacyjnym Apache
znajdź folder conf (domyślnie jest to folder C:\Program Files\Apache Software Foundation\Apache2.2\conf) i wybierz znajdujący się w nim plik httpd.conf. Aby można było ten plik otworzyć, na liście rozwijanej Pliki typu znajdującej się u dołu okna dialogowego Otwórz należy wybrać pozycję Wszystkie pliki. 3. W otwartym pliku znajdź pogrubiony poniżej wiersz, który zaczyna się od słowa DirectoryIndex:
DirectoryIndex index.html
Wiersz ten wskazuje serwerowi nazwy plików, jakich Apache powinien poszukać i zwrócić jako domyślną stronę dla danego katalogu. Na końcu wiersza należy dopisać nazwę pliku index.php:
DirectoryIndex index.html index.php
4. Wszystkie pozostałe opcje znajdujące się w tym długim i zniechęcającym
pliku konfiguracyjnym powinny być już prawidłowo skonfigurowane przez program instalacyjny serwera Apache. Dlatego pozostaje już tylko na samym końcu pliku dopisać następujące wiersze: LoadModule php5_module "C:/PHP/php5apache2_2.dll" AddType application/x-httpd-php .php PHPIniDir "C:/PHP"
Rozdział 1. ♦ Instalacja
33
Trzeba się przy tym upewnić, że wiersze LoadModule i PHPIniDir wskazują katalog instalacyjny języka PHP. Koniecznie należy też zwrócić uwagę na zastosowanie w ścieżkach znajdujących się w tych wierszach znaków ukośników (/) zamiast ukośników odwrotnych (\). PHP i przyszłe wersje serwera Apache W przeszłości każda nowa główna wersja serwera Apache wymagała podania nowej wersji pliku .dll w wierszu LoadModule przedstawionym powyżej. Gdy na przykład przyjrzysz się bliżej zawartości katalogu instalacyjnego języka PHP, zauważysz, że znajdują się w nim również pliki php5apache.dll oraz php5apache2.dll. Pliki te są przeznaczone odpowiednio do pracy z serwerem Apache 1.3 oraz Apache 2.0. Do czasu, gdy sięgniesz po tę książkę, być może Apache pojawi się już w kolejnej głównej wersji (na przykład jako Apache 2.3) i będzie wymagać kolejnego, nowego pliku .dll. Przykładowo wersja Apache 2.3 może wymagać pliku o nazwie php5apache2_3.dll. Jeżeli rzeczywiście używasz kolejnej wersji serwera Apache i widzisz, że istnieje plik .dll, którego nazwa jest zgodna z wersją serwera, wpisz nazwę tego pliku w wierszu LoadModule. Jeśli Apache nie będzie mógł załadować tego pliku, zawsze możesz przywrócić poprzednią postać wiersza LoadModule. 5. Zapisz zmiany i zamknij Notatnik. 6. Zrestartuj serwer Apache przy użyciu ikony Apache Service Monitor znajdującej
się w pasku narzędzi systemowych. Jeżeli wszystko pójdzie dobrze, Apache zostanie uruchomiony bez komunikatu o błędzie. 7. Dwukrotnie kliknij myszą ikonę Apache Service Monitor, aby otworzyć narzędzie
Apache Service Monitor. Jeżeli PHP został zainstalowany prawidłowo, pasek stanu okna tego narzędzia powinien wskazywać wersję zainstalowanego języka PHP w sposób widoczny na rysunku 1.15. Rysunek 1.15. Numer wersji języka PHP wskazuje, że Apache został skonfigurowany do jego obsługi
8. Kliknij przycisk OK, aby zamknąć okno Apache Service Monitor.
34
PHP i MySQL. Witryna WWW oparta na bazie danych
Skoro mamy już zainstalowany system MySQL i język PHP, możemy przejść do podrozdziału „Zadania poinstalacyjne”.
Instalowanie w systemie Mac OS X System Mac OS X reklamuje się jako jedyny przeznaczony dla przeciętnego konsumenta system operacyjny, który instaluje serwer Apache i PHP w każdej standardowej wersji. Z kolei zainstalowanie dodatkowo serwera baz danych MySQL wymaga tylko kilku nieskomplikowanych czynności. W tej części rozdziału pokażę, w jaki sposób na komputerze Mac z systemem operacyjnym Mac OS X w wersji 10.5 (Leopard) uruchomić serwer WWW z PHP i MySQL. Co jest potrzebne do zainstalowania w systemie Mac OS X najnowszych wersji PHP i MySQL? Jeżeli używasz komputera innego niż Mac, możesz z czystym sumieniem ominąć ten podrozdział.
Jednoczesna instalacja wszystkich komponentów Zwykle zalecam, aby serwer WWW, PHP oraz MySQL instalować i konfigurować oddzielnie, każdy z oficjalnego, odrębnego pakietu instalacyjnego. Jest to podejście szczególnie przydatne dla użytkowników początkujących, ponieważ dzięki temu łatwiej zrozumieć zależności między poszczególnymi komponentami. Jeśli jednak nie masz czasu na instalowanie oddzielnie poszczególnych elementów albo chcesz na dzień lub dwa utworzyć tymczasowe środowisko rozwojowe, zapewne wygodniejsze będzie opisywane w tym punkcie rozwiązanie minimalistyczne. Gdy jesteś gotów na to, by poświęcić nieco więcej czasu i zainstalować poszczególne komponenty oddzielnie, możesz przejść od razu do punktu „Instalacja poszczególnych komponentów”. Pakiet MAMP (słowo MAMP to skrót od nazw Mac, Apache, MySQL i PHP) jest darmowym, zbiorczym programem, który zawiera wbudowane kopie najnowszych wersji serwera WWW Apache, języka PHP oraz serwera baz danych MySQL. Spójrzmy, jak przebiega proces instalacji przy użyciu pakietu MAMP. 1. Pobierz najnowszą wersję pakietu z witryny MAMP7. Po pobraniu pliku (w czasie
pisania tej książki MAMP 1.7.2 miał około 130 MB), trzeba go dwukrotnie kliknąć myszą, aby rozpakować archiwum i uzyskać obraz dysku (MAMP_1.7.2.dmg). Potem jeszcze raz trzeba obraz dysku dwukrotnie kliknąć myszą, by zamontować dysk, jak na rysunku 1.16. 2. Zgodnie z instrukcjami widocznymi w oknie obrazu dysku, należy przeciągnąć
ikonę folderu MAMP na ikonę Applications, aby zainstalować pakiet MAMP
7
http://www.mamp.info
Rozdział 1. ♦ Instalacja
35
Rysunek 1.16. Pakiet MAMP
w systemie. Gdy kopiowanie dobiegnie końca, można przeciągnąć ikonę MAMP z pulpitu do ikony kosza na śmieci, aby ją wysunąć (ikona przekształci się w ikonę Wysuń), po czym usunąć obraz dysku, a także pobrany na początku oryginalny plik .zip. Przejdź do folderu Programy i odszukaj w nim nowy folder MAMP. Otwórz go i dwukrotnie kliknij myszą znajdującą się w nowym folderze ikonę MAMP. W trakcie uruchamiania MAMP najpierw pojawi się na ekranie okno MAMP, takie jak na rysunku 1.17, a widoczne w nim dwa wskaźniki stanu zmienią kolor z czerwonego na zielony, co będzie znakiem, że serwery Apache i MySQL rozpoczęły pracę. Następnie MAMP otworzy domyślną przeglądarkę internetową i w niej stronę powitalną pakietu, widoczną na rysunku 1.18. Rysunek 1.17. Okno MAMP
36
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 1.18. Strona powitalna MAMP zawiera potwierdzenie, że Apache, PHP i MySQL już działają
Po zakończeniu pracy z MAMP pakiet (wraz z wchodzącymi w jego skład serwerami) można zamknąć, klikając w oknie MAMP przycisk Quit. Gdy później ponownie trzeba będzie rozpocząć pracę nad witryną opartą na bazie danych, wystarczy ponownie uruchomić MAMP! W dalszej części książki trzeba będzie używać niektórych programów wchodzących w skład serwera MySQL stanowiącego część pakietu MAMP. Do prawidłowej pracy programy te wymagają dodania ich ścieżki dostępu do ścieżki systemu Mac OS X. Aby dodać programy wiersza poleceń serwera MySQL zainstalowanego w ramach MAMP do ścieżki systemu Mac OS X, należy wykonać następujące instrukcje. 1. Otwórz okno Terminal8. Jeżeli pracujesz w systemie Mac OS X w wersji 10.5 (Leopard)
lub późniejszej, wpisz następujące polecenia: Komputer:~ użytkownik$ sudo su Password: (podaj hasło) sh-3.2# echo '/Applications/MAMP/Library/bin' >> /etc/paths.d/MAMP sh-3.2# exit
Co dokładnie wpisać? Fragment Komputer:~ użytkownik$ (gdzie Komputer to nazwa komputera) reprezentuje aktualnie wyświetlany znak zachęty. Twoim zadaniem jest jedynie wpisanie poleceń wskazanych pogrubioną czcionką. Jeżeli używasz systemu w wersji 10.4 (Tiger) lub starszej, wpisz następujące
polecenia: Komputer:~ użytkownik$ touch .profile Komputer:~ użytkownik$ open .profile
W ten sposób w programie TextEdit otwarty zostanie ukryty plik .profile. Zawiera on listę poleceń okna Terminal wykonywanych automatycznie za każdym razem, gdy otwierane jest nowe okno Terminal. Jeżeli nigdy
8
Aby otworzyć okno Terminal, należy uruchomić aplikację Terminal, która z kolei znajduje się w podfolderze Utilities folderu Applications.
Rozdział 1. ♦ Instalacja
37
wcześniej nie instalowałeś w systemie programów wiersza poleceń, plik ten będzie pusty. Niezależnie od zawartości pliku .profile, na jego końcu należy dopisać następujący wiersz: export PATH=$PATH: /Applications/MAMP/Library/bin
Zmiany trzeba zapisać i zakończyć pracę programu TextEdit. 2. Zamknij okno Terminal, aby zatwierdzić wprowadzone zmiany.
Instalacja poszczególnych komponentów Instalowanie pojedynczych komponentów oddzielnie jest najlepszym rozwiązaniem, o ile tylko ma się wystarczającą ilość czasu. Można wówczas zorientować się, jak poszczególne składniki współpracują ze sobą, a jednocześnie zyskuje się możliwość uaktualniania poszczególnych składników rozwiązania niezależnie od pozostałych. Poza tym zawsze warto poznać sposób działania oprogramowania, z którego będzie się w przyszłości intensywnie korzystać. W punkcie tym zakładam, że używasz systemu Mac OS X 10.5 (Leopard) lub nowszego. Jeżeli używasz wcześniejszej wersji systemu Mac OS X, powinieneś skorzystać z opisanej wcześniej opcji jednoczesnego zainstalowania wszystkich komponentów.
Instalowanie serwera baz danych MySQL Apple udostępnia na swojej witrynie Mac OS X Internet Developer9 dość wyczerpujący przewodnik. Osobom, które chcą samodzielnie skompilować serwer MySQL, wyjaśnia on, jak instalować MySQL w systemie Mac OS X. Znacznie prościej jednak pobrać już skompilowane, binarne pliki serwera wprost z witryny MySQL. Aby zainstalować serwer MySQL w takim systemie, należy najpierw przejść do strony Downloads witryny MySQL10 i kliknąć łącze Download w kolumnie odpowiadającej darmowej wersji MySQL Community Server. W odpowiedzi wyświetlona zostanie długa lista łączy umożliwiających pobranie różnych, rekomendowanych wersji aktualnego wydania serwera MySQL (w trakcie powstawania tej książki wersją bieżącą była wersja MySQL 5.1). Na liście należy kliknąć pozycję Mac OS X (package format). Na ekranie pojawi się wówczas lista plików dostępnych do pobrania, widoczna na rysunku 1.19. Konkretna wersja, którą należy wybrać, zależy od używanej wersji systemu operacyjnego oraz architektury platformy. Jeżeli używanym systemem operacyjnym jest Mac OS X 10.5 (Leopard), wówczas można pominąć łącza dotyczące wersji Mac OS X 10.4. Jeżeli wiesz, że komputer Mac, którego używasz, posiada procesor zbudowany w architekturze 64-bitowej, możesz wybrać wersję Mac OS X 10.5 (x86_64). Jeżeli natomiast nie masz takiej pewności, najlepiej będzie wybrać wersję Mac OS X 10.5 (x86), która 9
http://developer.apple.com/internet/macosx/osdb.html
10
http://dev.mysql.com/downloads/
38
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 1.19. Wersja serwera MySQL dla komputerów 32-bitowych z procesorem Intel będzie działać na większości aktualnie używanych komputerów Mac
wymaga jedynie komputera Mac z procesorem Intel (aby zyskać całkowitą pewność, należy sprawdzić informacje o używanym procesorze, wyświetlane w oknie Ten Macintosh, dostępnym w menu Apple). Jeżeli używasz starszego komputera Mac opartego na procesorze PowerPC, będziesz musiał wybrać jedną z wersji dla komputerów PowerPC. Najlepszym wyborem jest w takiej sytuacji wersja 32-bitowa, ponieważ będzie ona działać także w systemie 64-bitowym. Gdy już pobierzesz plik mysql-wersja-osxwersja-platforma.dmg, należy kliknąć go dwukrotnie, by zamontować obraz dyskowy. Jak pokazano na rysunku 1.20, obraz zawiera program instalacyjny (ang. installer) w formacie .pkg oraz plik MySQLStartupItem.pkg. Następnie trzeba uruchomić program instalacyjny, klikając go dwukrotnie, a on przeprowadzi nas przez proces instalacji systemu MySQL. Rysunek 1.20. Pakiet MySQL Mac OS X zawiera wiele ciekawych elementów
Po zainstalowaniu systemu MySQL można uruchomić serwer MySQL, otwierając okno Terminal11 i wpisując następujące polecenie: Komputer:~ użytkownik$ sudo /usr/local/mysql/bin/mysqld_safe
Co dokładnie wpisać? Fragment Komputer:~ użytkownik$ (gdzie Komputer to nazwa komputera) reprezentuje aktualnie wyświetlany znak zachęty. Twoim zadaniem jest jedynie wpisanie poleceń wskazanych pogrubioną czcionką.
11
Aby otworzyć okno Terminal, należy uruchomić aplikację Terminal, która z kolei znajduje się w podfolderze Narzędzia folderu Programy.
Rozdział 1. ♦ Instalacja
39
Po wpisaniu polecenia trzeba nacisnąć klawisz Enter. Przedstawione polecenie uruchomi skrypt mysqld_safe z uprawnieniem administratora. Aby wykonać skrypt, trzeba podać hasło administratora; potem komunikat stanu poinformuje, że serwer MySQL już działa. Gdy serwer MySQL będzie działał, można przełączyć go na pracę w tle. W tym celu trzeba nacisnąć Ctrl+Z, aby zatrzymać proces, po czym wpisać poniższe polecenie, aby proces ponownie uruchomić w tle: Komputer:~ użytkownik$ bg
Teraz można zamknąć okno Terminal. Od tej pory MySQL działa w naszym systemie jako serwer baz danych. Aby zakończyć pracę serwera MySQL, wystarczy ponownie otworzyć okno Terminal i wpisać następujące polecenie: Komputer:~ użytkownik$ sudo /usr/local/mysql/bin/mysqladmin shutdown
Dla zwykłego śmiertelnika zapamiętanie tych wszystkich tajemniczo brzmiących poleceń jest dość trudnym zadaniem. Na szczęście, istnieje znacznie prostszy sposób sprawowania kontroli nad pracą serwera MySQL. Aby z niego skorzystać, należy wrócić do obrazu dysku instalacyjnego widocznego na rysunku 1.20. Widać na nim plik o nazwie MySQL.prefPane; w nim po dwukrotnym kliknięciu myszą w opcjach systemu Preferencje systemowe Mac OS X zainstalowany zostanie nowy panel oraz otwarte okno widoczne na rysunku 1.21. Rysunek 1.21. Panel MySQL w Preferencje systemowe
W oknie znajduje się informacja, czy MySQL działa, czy nie. Można w nim także uruchamiać serwer i kończyć jego pracę tylko jednym kliknięciem myszy! Warto również tak skonfigurować system, by w momencie jego uruchomienia automatycznie włączał serwer MySQL. Unikniemy w ten sposób konieczności czynienia tego ręcznie przy każdym włączeniu komputera. W nowym panelu opcji Preferencje systemowe znajduje się odpowiednie pole wyboru, jednak aby jego zaznaczenie dało jakikolwiek efekt, trzeba najpierw zainstalować program MySQLStartupItem.pkg wchodzący w skład obrazu dysku instalacyjnego.
40
PHP i MySQL. Witryna WWW oparta na bazie danych
Gdy już się uporamy z wykonaniem wszystkich czynności instalacyjnych, można umieścić w koszu podpięty dysk, z którego dokonywaliśmy instalacji pakietu MySQL, a następnie usunąć plik .dmg. Ostatnim zadaniem, jakie warto wykonać, jest dodanie katalogu /usr/local/mysql/bin do ścieżki systemowej. Dzięki temu programy, takie jak mysqladmin i mysql (których będziemy intensywnie używać w dalszych rozdziałach książki), uruchomimy w oknie Terminal bez wpisywania ich pełnych ścieżek dostępu. W tym celu należy otworzyć okno Terminal i wpisać następujące polecenia: Komputer:~ użytkownik$ sudo su Password: (wpisz hasło) sh-3.2# echo '/usr/local/mysql/bin' >> /etc/path.d/mysql sh-3.2# exit
Okno Terminal trzeba następnie zamknąć i otworzyć nowe, aby wprowadzone zmiany zostały uwzględnione w systemie operacyjnym. Następnie, gdy serwer MySQL cały czas będzie działał, z poziomu własnego katalogu głównego należy spróbować uruchomić program mysqladmin: Komputer:~ użytkownik$ mysqladmin status
Jeżeli wszystkie przytoczone polecenia zostały wykonane prawidłowo, w odpowiedzi powinna pojawić się krótka lista statystyk na temat serwera MySQL.
Instalowanie języka PHP Mac OS X w wersji 10.5 (Leopard) posiada już wbudowane Apache 2.2 i PHP 5! Aby skorzystać z nich dla celów prac rozwojowych, wystarczy obydwa komponenty włączyć w następujący sposób. 1. Otwórz opcje systemu (polecenie Preferencje systemowe w menu Apple). 2. W głównym menu Preferencje systemowe, w sekcji Internet i sieć kliknij
polecenie Udostępnianie. 3. Upewnij się, że pole wyboru Udostępnianie www jest zaznaczone, jak pokazano
na rysunku 1.22. Rysunek 1.22. Włączenie opcji Udostępnianie w Mac OS X
Rozdział 1. ♦ Instalacja
41
4. Zamknij okno Preferencje systemowe. 5. Otwórz przeglądarkę internetową, w jej pasku adresów wpisz adres
http://localhost i naciśnij klawisz Enter. W przeglądarce powinna zostać wyświetlona strona powitalna serwera Apache przedstawiona na rysunku 1.23.
Rysunek 1.23. Standardowa strona powitalna serwera Apache
Po zrealizowaniu opisanej procedury Apache będzie automatycznie uruchamiany w systemie operacyjnym. Można więc rozszerzyć jego możliwości o obsługę języka PHP. 1. W pasku menu Finder wybierz polecenie Idź/Idź do katalogu (×+a+G) i wpisz
/private/etc/apache2, po czym kliknij Idź. 2. W oknie Finder, które zostanie w ten sposób otwarte, powinien znajdować się
plik httpd.conf — jest to plik konfiguracyjny serwera Apache. Domyślnie jest dostępny wyłącznie do odczytu. Plik należy kliknąć prawym przyciskiem myszy i wybrać polecenie Informacje (a+I), aby wyświetlić właściwości pliku. W dolnej części okna Informacja: httpd.conf należy znaleźć ustawienie Udostępnianie i uprawnienia. Domyślnie ustawienia znajdujące się w tej sekcji są wyłączone. Kliknij myszą niewielką ikonę kłódki widoczną na rysunku 1.24, aby je włączyć. Jeśli trzeba, wpisz hasło. Rysunek 1.24. Aby zmienić ustawienia, trzeba kliknąć ikonę kłódki
Żeby włączyć możliwość edycji pliku, należy zmienić wartość znajdującą się w kolumnie Przywilej dla użytkowników everyone na odczyt i zapis, jak pokazano na rysunku 1.25.
42
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 1.25. Użytkownikom everyone należy nadać uprawnienie odczyt i zapis
3. Po powrocie do okna Finder dla folderu apache2 kliknij prawym przyciskiem
myszy tło okna folderu i wybierz polecenie Informacje, aby otworzyć właściwości folderu. Podobnie jak w poprzednim kroku, uprawnienie Udostępnianie i uprawnienia należy ustawić dla everyone na wartość odczyt i zapis. 4. Na końcu dwukrotnie kliknij myszą plik httpd.conf, aby otworzyć go w edytorze
TextEdit. 5. W pliku httpd.conf poszukaj następującego wiersza: #LoadModule php5_module
libexec/apache2/libphp5.so
Powyższe polecenie trzeba włączyć przez usunięcie znaku # na początku wiersza. 6. Zapisz zmiany i zamknij TextEdit. 7. Jeśli lubisz zostawiać po sobie porządek, możesz przywrócić oryginalne
ustawienia dostępu dla pliku httpd.conf i folderu apache2. Dzięki temu inni użytkownicy komputera nie będą mogli zmienić ustawień serwera Apache. 8. Otwórz okno Terminal i wpisz następujące polecenie, które zrestartuje serwer
Apache: Komputer:~ użytkownik$ sudo /usr/sbin/apachectl restart
Na żądanie wpisz hasło. 9. W przeglądarce ponownie wpisz adres http://localhost, aby upewnić się,
że Apache wciąż działa. Komputer jest już wyposażony w serwer Apache z obsługą języka PHP. Jeżeli trzeba będzie wprowadzić zmiany w konfiguracji serwera Apache, bez trudu można edytować plik httpd.conf zgodnie z instrukcjami podanymi powyżej. Jednak wtyczka obsługująca PHP posiada własny plik konfiguracyjny o nazwie php.ini, który również trzeba odpowiednio zmienić, aby wskazać sposób łączenia się PHP z serwerem baz danych MySQL. Wersja języka PHP wbudowana w systemie operacyjnym Mac OS X nie posiada domyślnie pliku php.ini; PHP po prostu jest uruchamiany z ustawieniami domyślnymi. Aby je zmienić, trzeba otworzyć Terminal i skopiować plik /private/etc/php.ini.default do pliku /private/etc/php.ini: Komputer:~ użytkownik$ cd /private/etc Komputer:~ użytkownik$ sudo cp php.ini.default php.ini Password:(wpisz hasło)
Aby nowy plik php.ini stał się dostępny do edycji dla zwykłych użytkowników, należy wykonać te same czynności, które opisano w kontekście edycji pliku httpd.conf, to
Rozdział 1. ♦ Instalacja
43
znaczy w narzędziu Finder trzeba wybrać polecenie Idź/Idź do katalogu i otworzyć folder /private/etc, następnie zmienić uprawnienia do pliku php.ini i samego folderu, w którym ten plik się znajduje, a na końcu otworzyć plik w TextEdit. W kolejnym kroku trzeba przewinąć zawartość pliku albo wykorzystać polecenie Edycja/Znajdź/Znajdź… (a+F), aby znaleźć opcję mysql.default_socket. Odnaleziony wiersz pliku php.ini należy zmienić w taki sposób, aby przybrał postać: mysql.default_socket = /tmp/mysql.sock
Cała zmiana polega wyłącznie na dodaniu fragmentu zaznaczonego pogrubioną czcionką. Następnie trzeba dalej przewinąć zawartość pliku i odnaleźć wiersz z opcją mysqli. ´default_socket (mysqli, nie mysql), po czym wprowadzić zmianę, podobną jak przed chwilą: mysqli.default_socket = /tmp/mysql.sock
Zmiany należy zapisać, wyjść z programu TextEdit i w razie potrzeby przywrócić oryginalne uprawnienia do pliku i katalogu. Na koniec należy otworzyć okno Terminal i wpisać polecenie, które znów wykona restart serwera Apache: Komputer:~ użytkownik$ sudo /usr/sbin/apachectl restart
W odpowiednim momencie należy podać hasło. Gdy serwer Apache będzie już znowu gotowy do pracy, w przeglądarce internetowej ponownie wpisać adres http://localhost, aby upewnić się, że wszystko działa poprawnie. I to już wszystko! Po pomyślnym zainstalowaniu komponentów MySQL, Apache i PHP możesz przejść do punktu pod tytułem „Zadania poinstalacyjne”.
Instalacja w systemie Linux W tej części rozdziału zostanie opisana procedura instalowania języka PHP i systemu MySQL dla najnowszych dystrybucji Linuksa. Instrukcje instalacji były testowane na dystrybucji Ubuntu 8.1012, niemniej powinny bez większych problemów sprawdzać się również w innych dystrybucjach, takich jak Fedora13, Debian14, openSUSE15 czy Gentoo16. Kolejne etapy procedury będą bardzo podobne, jeśli nie wręcz identyczne.
12
http://www.ubuntu.com
13
http://fedoraproject.org
14
http://www.debian.org
15
http://www.opensuse.org
16
http://www.gentoo.org
Rozdział 1. ♦ Instalacja
45
Po ściągnięciu pliku na komputer należy otworzyć okno Terminal i zalogować się w systemie jako użytkownik root: użytkownik@komputer:~$ sudo su
Oczywiście, konieczne będzie podanie hasła. Teraz trzeba przejść do katalogu /usr/local i rozpakować pobrany plik: root@komputer:/home/użytkownik# cd /usr/local root@komputer:/usr/local# tar xfz ~użytkownik/Desktop/mysql-wersja-linuxplatforma.tar.gz
W drugim poleceniu przyjęto założenie, że pobrany plik został zapisany na pulpicie, czyli w katalogu Desktop własnego katalogu macierzystego. Element użytkownik należy zastąpić nazwą użytkownika, zamiast wersja trzeba wpisać wersję pobranego serwera baz danych MySQL, zaś platforma powinna zostać zastąpiona oznaczeniem odpowiedniej wersji architektury i kompilatora pobranej wersji serwera. Inaczej mówiąc, ścieżka dostępu do pliku w poleceniu powinna być identyczna ze ścieżką dostępu i nazwą pliku pobranego z Internetu. Przykładowo na moim komputerze to konkretne polecenie ma następującą postać: root@mythril:/usr/local# tar xfz ~kyank/Desktop/ ´mysql-5.1.34-linux-x86_64-glibc23.tar.gz
Po upływie jednej czy dwóch minut nastąpi powrót do symbolu zachęty. Krótkie polecenie ls pozwoli stwierdzić, że rzeczywiście powstał nowy katalog o nazwie mysqlwersja-linux-platforma. Na moim komputerze wygląda to następująco: root@mythril:/usr/local# ls bin games lib mysql-5.1.34-linux-x86_64-glibc23 etc include man sbin
share src
Następnym krokiem jest utworzenie powiązania symbolicznego o nazwie mysql, aby ułatwić sobie dostęp do katalogu. Potem trzeba wpisać nazwę katalogu: root@komputer:/usr/local# ln -s mysql-wersja-linux-platforma mysql root@komputer:/usr/local# cd mysql
Mimo iż można uruchamiać serwer MySQL z uprawnieniami użytkownika root lub nawet ze swoimi własnymi (jeśli na przykład zainstalowaliśmy serwer w katalogu home), niewątpliwie najlepszym rozwiązaniem jest przygotowanie w systemie specjalnego użytkownika, służącego tylko i wyłącznie do uruchamiania serwera MySQL. W ten sposób unikniemy niebezpieczeństwa, że ktoś z zewnątrz wykorzysta serwer MySQL, by włamać się do reszty naszego systemu. Aby przygotować specjalnego użytkownika MySQL, należy zalogować się w systemie jako użytkownik root i wpisać następujące polecenia: root@komputer:/usr/local/mysql# groupadd mysql root@komputer:/usr/local/mysql# useradd -g mysql mysql
W kolejnym kroku trzeba wskazać nowego użytkownika jako właściciela katalogu MySQL:
46
PHP i MySQL. Witryna WWW oparta na bazie danych root@komputer:/usr/local/mysql# chown –R mysql . root@komputer:/usr/local/mysql# chgrp -R mysql .
W tym momencie serwer baz danych MySQL będzie już zainstalowany. Zanim jednak posłużymy się nim, trzeba zainstalować pliki jego bazy danych. W tym celu w nowym katalogu mysql należy wpisać następujące polecenie: root@komputer:/usr/local/mysql# scripts/mysql_install_db --user=mysql
Teraz jesteśmy już gotowi do pierwszego uruchomienia serwera MySQL. W tym celu należy w katalogu MySQL wpisać następujące polecenie: root@komputer:/usr/local/mysql# bin/mysqld_safe --user=mysql &
Jeśli pojawi się komunikat mysql daemon ended, oznaczać to będzie, że coś uniemożliwiło uruchomienie serwera MySQL. Ten komunikat o błędzie powinien zostać również zapisany w pliku o nazwie nazwahosta.err (gdzie nazwahosta jest — oczywiście — nazwą hosta naszego komputera) w katalogu data systemu MySQL. Zazwyczaj dzieje się tak dlatego, że na naszym komputerze działa już inny serwer MySQL. Jeśli natomiast uda się uruchomić serwer MySQL bez żadnych komunikatów o błędach, serwer bazy danych (podobnie jak serwer WWW lub FTP) będzie działał do chwili wyłączenia komputera. Aby sprawdzić, czy serwer MySQL działa prawidłowo, wystarczy wpisać następujące polecenie: root@komputer:/usr/local/mysql# bin/mysqladmin -u root status
W tym momencie ukaże się ciąg komunikatów ze statystykami serwera MySQL. Jeśli natomiast pojawi się komunikat o błędzie, oznacza to wystąpienie jakiegoś problemu. Należy wówczas ponownie zajrzeć do pliku błędów nazwahosta.err, by sprawdzić, czy serwer MySQL w momencie uruchamiania wygenerował jakiś komunikat o błędzie. Jeśli powtórzenie czynności opisanych powyżej nie rozwiąże problemów, można wysłać zapytania na SitePoint Forums20, co pozwoli zaoszczędzić sporo cennego czasu. Aby serwer MySQL włączał się automatycznie w momencie uruchomienia systemu (tak prawdopodobnie funkcjonuje nasz serwer WWW), trzeba go odpowiednio skonfigurować. W katalogu mysql znajduje się podkatalog support-files, w którym można znaleźć skrypt o nazwie mysql.server. W większości wersji Linuksa można w tym celu w katalogu /etc/init.d utworzyć powiązanie do skryptu mysql.server, a następnie zdefiniować dwa łącza do niego: /etc/rc2.d/S99mysql oraz /etc/rc0.d/K01mysql. Oto polecenia, które trzeba wykonać: root@komputer:/usr/local/mysql# cd /etc root@komputer:/etc# ln –s /usr/local/mysql/support-files/mysql.server init.d/ root@komputer:/etc# ln –s /etc/init.d/mysql.server rc2.d/S99mysql root@komputer:/etc# ln –s /etc/init.d/mysql.server rc0.d/K01mysql
I to wszystko! Aby sprawdzić, czy wszystko działa prawidłowo, należy wykonać restart systemu i poleceniem mysqladmin sprawdzić stan serwera, zgodnie z opisem podanym wcześniej. 20
http://www.sitepoint.com/forums/
Rozdział 1. ♦ Instalacja
47
Ostatnią czynnością, którą warto wykonać dla własnej wygody, jest umieszczenie na ścieżce systemowej programów klientów MySQL, których później użyjemy do administrowania serwerem MySQL. W tym celu należy w katalogu /usr/local/bin umieścić powiązania symboliczne do programów mysql, mysqladmin i mysqldump: root@komputer:/etc# cd /usr/local/bin root@komputer:/usr/local/bin# ln -s /usr/local/mysql/bin/mysql . root@komputer:/usr/local/bin# ln -s /usr/local/mysql/bin/mysqladmin . root@komputer:/usr/local/bin# ln -s /usr/local/mysql/bin/mysqldump .
Po wykonaniu opisanych czynności można wylogować się z konta użytkownika root. Od tego momentu administrowanie serwerem MySQL będzie możliwe z dowolnego katalogu systemu: root@komputer:/usr/local/bin# exit root@komputer:~$ mysqladmin –u root status
Instalowanie języka PHP Jak już wspomniano, język PHP jest właściwie dodatkowym modułem współpracującym z serwerem WWW. Zasadniczo istnieją trzy sposoby instalowania dodatku PHP w serwerze Apache. Jako program CGI, który serwer Apache uruchamia za każdym razem, gdy musi
przetwarzać stronę WWW korzystającą z kodu PHP. Jako moduł serwera Apache wkompilowany wprost do serwera Apache. Jako osobny moduł serwera Apache, ładowany przy każdym uruchomieniu
serwera. Pierwsze rozwiązanie jest najłatwiejsze, jeśli chodzi o instalowanie i konfigurowanie, wymaga jednak od serwera Apache, by uruchamiał język PHP jako osobny program, ilekroć ktoś żąda strony wykorzystującej kod PHP. Konieczność uruchamiania coraz to nowych programów zwalnia działanie serwera WWW i wydłuża czas potrzebny na udzielenie odpowiedzi na żądanie, zwłaszcza gdy musi odpowiadać na więcej niż jedno żądanie jednocześnie. Rozwiązania drugie i trzecie zapewniają prawie identyczną wydajność serwera, jednak opcja trzecia jest najbardziej elastyczna, ponieważ umożliwia dodawanie i usuwanie modułów serwera Apache bez konieczności każdorazowego wykonywania rekompilacji. Dlatego właśnie wybierzemy trzecie rozwiązanie. Przy założeniu, że nie masz jeszcze serwera Apache zainstalowanego na swoim komputerze, przejdź na stronę Apache HTTP Server Project21 i poszukaj tej wersji serwera, która jest wskazana jako „best available version”, czyli najlepsza dostępna wersja (w momencie powstawania tej książki najlepszą dostępną wersją była wersja 2.2.11, co widać na rysunku 1.27).
21
http://httpd.apache.org/
48
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 1.27. Najlepsza dostępna wersja — interesują nas tylko najlepsze rozwiązania!
Po odnalezieniu strony Download należy ją przewinąć, aby odnaleźć łącza do poszczególnych dostępnych wersji serwera. Nas interesuje wersja Unix Source, wskazana na rysunku 1.28. Pliki .tar.gz i .tar.bz2 mają taką samą zawartość, dlatego można wybrać dowolny z tych dwóch, zależnie od preferowanego formatu. Rysunek 1.28. Wersja serwera Apache, której potrzebujemy
Pobrany plik zawiera kod źródłowy serwera Apache. Pierwszym krokiem jest skompilowanie go do postaci wykonywalnej, binarnej wersji instalacyjnej. Należy otworzyć okno Terminal, przejść do katalogu, w którym zapisany został pobrany plik, a następnie rozpakować archiwum, po czym przejść do katalogu wynikowego. użytkownik@komputer:~$ cd Desktop użytkownik@komputer:~/Desktop$ tar xfz httpd-wersja.tar.gz użytkownik@komputer:~/Desktop$ cd httpd-wersja
Aby skompilować serwer Apache, trzeba najpierw skonfigurować go zgodnie z wymaganiami. Dla naszych celów większość ustawień domyślnych w zupełności wystarczy; trzeba będzie jedynie włączyć dynamiczne ładowanie modułów Apache (takim modułem jest PHP), które domyślnie jest wyłączone. Ponadto konieczne może być włączenie funkcji przepisywania adresów URL, z której korzysta wiele aplikacji zaimplementowanych w PHP (nie dotyczy to jednak przykładów zawartych w tej książce). Aby wprowadzić odpowiednie zmiany w konfiguracji, należy wykonać następujące polecenie: użytkownik@komputer:~/Desktop/httpd-wersja$ ./configure --enable-so ´--enable-rewrite
Przez ekran przewinie się długi strumień komunikatów o statusie. Jeżeli proces konfiguracji zatrzyma się z komunikatem o błędzie, może to oznaczać, że w systemie operacyjnym brakuje pewnych kluczowych elementów oprogramowania wymaganych do przeprowadzenia kompilacji serwera Apache. W niektórych dystrybucjach Linuksa brakuje kluczowych bibliotek programistycznych, a czasami nawet kompilatora C, który zazwyczaj jest instalowany domyślnie. Zainstalowanie brakujących składników powinno spowodować, że ponowne wykonanie powyższego polecenia zakończy się pomyślnie. Aktualne wersje dystrybucji Ubuntu powinny zawierać wszystkie wymagane składniki oprogramowania.
Rozdział 1. ♦ Instalacja
49
Po kilku minutach strumień komunikatów powinien się zakończyć w następujący sposób: . . . config.status: creating build/rules.mk config.status: creating build/pkg/pkginfo config.status: creating build/config_vars.sh config.status: creating include/ap_config_auto.sh config.status: executing default commands użytkownik@komputer:~/Desktop/httpd-wersja$
W tym momencie możemy już przystąpić do skompilowania serwera Apache. Uruchomienie całego procesu polega jedynie na wykonaniu pojedynczego polecenia make: użytkownik@komputer:~/Desktop/httpd-wersja$ make
Ta czynność również będzie trwać kilka minut i powinna zakończyć się następującymi komunikatami: . . . make[1]: Leaving directory '/home/użytkownik/Desktop/httpd-wersja' użytkownik@komputer:~/Desktop/httpd-wersja$
Aby zainstalować dopiero co skompilowaną kopię serwera Apache, trzeba wpisać polecenie make install (wykonanie polecenia sudo jest konieczne, ponieważ aby zapisywać dane w katalogu instalacyjnym, potrzebne jest posiadanie uprawnień użytkownika root). użytkownik@komputer:~/Desktop/httpd-wersja$ sudo make install
W odpowiednim momencie trzeba będzie wpisać hasło. Gdy kopiowanie plików dobiegnie końca, będzie to znak, że również instalacja serwera Apache jest już zakończona. Należy zatem przejść do katalogu instalacyjnego i uruchomić serwer przy użyciu skryptu apachectl: użytkownik@komputer:~/Desktop/httpd-wersja$ cd /usr/local/apache2 użytkownik@komputer:/usr/local/apache2$ sudo bin/apachectl –k start
Apache prawdopodobnie wyświetli komunikat z ostrzeżeniem, że nie udało się ustalić w pełni kwalifikowanej nazwy domenowej serwera. Przyczyną jest fakt, że większość komputerów osobistych w ogóle nie posiada takiej nazwy. Nie ma więc powodów do niepokoju. Można już uruchomić przeglądarkę i w jej pasku adresu wpisać http://localhost. Jeżeli serwer Apache działa prawidłowo, w przeglądarce powinien pojawić się komunikat powitalny widoczny na rysunku 1.29. Podobnie jak to było z serwerem baz danych MySQL, warto skonfigurować Apache w taki sposób, aby uruchamiał się automatycznie wraz z uruchomieniem systemu operacyjnego. Procedura przebiega analogicznie: wystarczy skopiować skrypt apachectl z katalogu instalacyjnego Apache i utworzyć odpowiednie powiązanie.
50
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 1.29. Potwierdzenie, że Apache działa prawidłowo
użytkownik@komputer:/usr/local/apache2$ sudo su root@komputer:/usr/local/apache2# cd /etc root@komputer:/etc# ln –s /usr/local/apache2/bin/apachectl init.d/ root@komputer:/etc# ln –s /etc/init.d/apachectl rc2.d/S99httpd root@komputer:/etc# ln –s /etc/init.d/apachectl rc0.d/K01httpd
Aby sprawdzić, czy wszystko działa prawidłowo, trzeba zrestartować komputer i w przeglądarce internetowej ponownie wywołać adres http://localhost, Po pomyślnym zainstalowaniu serwera Apache można przystąpić do rozszerzenia go o obsługę języka PHP. Aby rozpocząć instalację, należy pobrać pakiet PHP Complete Source Code ze strony PHP Downloads22. Również w tym przypadku pliki .tar.gz i .tar.bz2 mają identyczną zawartość, dlatego wystarczy pobrać tylko jeden z nich, zależnie od własnych preferencji. Plik, który ściągniemy, powinien nosić nazwę php-wersja.tar.gz (albo .bz2). Należy otworzyć nowe okno Terminal, przejść do katalogu zawierającego pobrany plik, rozpakować go i przenieść do katalogu wynikowego: użytkownik@komputer:~$ cd Desktop użytkownik@komputer:~/Desktop$ tar xfz php-wersja.tar.gz użytkownik@komputer:~/Desktop$ cd php-wersja
Aby zainstalować język PHP jako moduł serwera Apache, potrzebny będzie program apxs. Jeżeli serwer Apache został zainstalowany zgodnie z przedstawionymi wcześniej instrukcjami kompilacji, program apxs będzie od razu dostępny. Jeśli jednak korzystamy z wersji serwera udostępnianej wraz z naszym systemem Linux, może go nie być wśród programów i konieczne będzie doinstalowanie pakietu „Apache developement” serwera Apache. Pakiet ten powinien się bez trudu zainstalować za pomocą menedżera pakietów obecnego w dystrybucji Linuksa. Przykładowo w systemie Debian Linux można go zainstalować, używając zwyczajowego narzędzia apt-get: użytkownik@komputer:~$ sudo apt-get install apache-dev
W celu wykonania pozostałej części procedury instalacji PHP konieczne będzie zalogowanie się jako użytkownik root: użytkownik@komputer:~/Desktop/php-wersja$ sudo su [sudo] password for użytkownik: (wpisz hasło) root@komputer:/home/użytkownik/Desktop/php-wersja#
22
http://www.php.net/downloads.php
Rozdział 1. ♦ Instalacja
51
W pierwszym kroku należy skonfigurować program instalacyjny PHP, informując go, które opcje chcemy włączyć i gdzie może znaleźć niezbędne programy (takie jak program apxs serwera Apache i serwer MySQL). Odpowiednie polecenie powinno mieć następującą postać (wszystko w jednym wierszu): root@komputer:/home/użytkownik/Desktop/php-wersja# ./configure -prefix=/usr/local/php --with-apxs2=/usr/local/apache2/bin/apxs --withmysqli=/usr/local/mysql/bin/mysql_config
Opcja --prefix wskazuje programowi instalacyjnemu lokalizację, w której należy zainstalować PHP (dobrym rozwiązaniem jest wskazanie katalogu /usr/local/php). Opcja --with-apxs2 wskazuje programowi instalacyjnemu lokalizację, w której znajduje się wspomniany przed chwilą program apxs. Jeżeli program jest instalowany przy użyciu menedżera pakietów dystrybucji Linuksa, zwykle jest umieszczany w katalogu /usr/bin/apxs. Jeżeli natomiast kompilowałeś i instalowałeś serwer Apache samodzielnie, zgodnie z opisem przedstawionym wyżej, program będzie się znajdował w katalogu binariów serwera, czyli /usr/local/apache2/bin/apxs. Opcja --with-mysqli wskazuje programowi instalacyjnemu lokalizację, w której znajduje się pakiet instalacyjny serwera baz danych MySQL. Mówiąc bardziej precyzyjnie, opcja musi wskazywać program mysql_config znajdujący się w katalogu bin katalogu instalacyjnego MySQL (/usr/local/mysql/bin/mysql_config). Tak jak poprzednio, przez ekran przewinie się cała lista komunikatów statusu. Gdy proces dobiegnie końca, należy sprawdzić, czy nie pojawiły się jakieś komunikaty o błędach i doinstalować wszystkie brakujące pliki. Przykładowo w domyślnej instalacji dystrybucji Ubuntu 8.10 prawdopodobnie zwrócony zostanie błąd informujący o niepełnej instalacji biblioteki libxml2. Aby usunąć ten konkretny błąd, należy otworzyć program Synaptic Package Manager, a następnie zlokalizować i zainstalować pakiet libxml2-dev (biblioteka libxml2 powinna być już zainstalowana). Po zakończeniu instalacji należy ponownie wykonać polecenie configure. Gdy już przewinie się kilka ekranów informujących o wykonywanych testach, powrócimy do wiersza poleceń zawierającego miły dla oka komunikat "Thank you for using PHP". Następnie należy wpisać dwa standardowe polecenia, które skompilują i zainstalują PHP. root@komputer:/home/użytkownik/Desktop/php-wersja# make root@komputer:/home/użytkownik/Desktop/php-wersja# make install
Możemy sobie zrobić przerwę na kawę, to chwilę potrwa. Po wykonaniu polecenia make install język PHP zostanie zainstalowany w katalogu /usr/local/php (chyba że podamy inny katalog, korzystając z opcji --prefix wspomnianego wyżej skryptu configure). Teraz pozostaje już tylko skonfigurować moduł obsługi języka! Plik konfiguracyjny PHP nosi nazwę php.ini. PHP jest instalowany wraz z dwoma przykładowymi plikami konfiguracyjnymi php.ini, noszącymi nazwy php.ini-dist oraz
52
PHP i MySQL. Witryna WWW oparta na bazie danych
php.ini-recommended. Pliki te należy skopiować z roboczego katalogu instalacyjnego do katalogu /usr/local/php/lib, a następnie utworzyć kopię pliku php.ini-dist i nadać jej nazwę php.ini: root@komputer:/home/użytkownik/Desktop/php-wersja# cp php.ini* /usr/local/php/lib/ root@komputer:/home/użytkownik/Desktop/php-wersja# cd /usr/local/php/lib root@komputer:/usr/local/php/lib# cp php.ini-dist php.ini
Teraz można już usunąć katalog roboczy, w którym kompilowaliśmy PHP — nie będzie już potrzebny. Kwestia poprawiania ustawień w pliku php.ini zostanie poruszona nieco dalej. Tymczasem jednak należy poprawić konfigurację serwera Apache, by upewnić się, że będzie przyjazna dla stron korzystających z PHP. W tym celu trzeba znaleźć plik konfiguracyjny serwera Apache httpd.conf — zazwyczaj można go znaleźć w podkatalogu /conf katalogu instalacyjnego serwera Apache (/usr/local/apache2/conf/httpd.conf). Aby edytować ten plik, trzeba zalogować się jako użytkownik root. Najlepiej więc ponownie otworzyć okno Terminal, w którym wciąż jesteś zalogowany jako root, i uruchomić w nim edytor tekstu: root@komputer:/usr/local/php/lib# cd /usr/local/apache2/conf root@komputer:/usr/local/apache2/conf# gedit httpd.conf
Następnie trzeba odnaleźć wiersz zaczynający się od DirectoryIndex. Wiersz ten informuje serwer Apache, z jakich nazw plików ma korzystać, gdy szuka domyślnej strony w danym katalogu. Standardowo jest to nazwa index.html, należy jednak dodać do listy również index.php:
DirectoryIndex index.html index.php
Na koniec musimy przejść na sam dół pliku i dodać tam wiersz informujący, że pliki z rozszerzeniem .php powinny być traktowane jak skrypty języka PHP:
SetHandler application/x-httpd-php
Po tych poprawkach zadanie zostało prawie ukończone. Należy tylko zapisać zmiany i ponownie uruchomić serwer Apache: root@komputer:/usr/local/apache2/conf# /usr/local/apache2/bin/apachectl –k restart
Jeśli wszystko pójdzie zgodnie z planem, serwer Apache powinien uruchomić się bez żadnych komunikatów o błędach. Jeśli pojawią się jakieś problemy, i tym razem pomocni mogą okazać się specjaliści z SitePoint Forums23, między innymi autor tej książki.
23
http://www.sitepoint.com/forums/
Rozdział 1. ♦ Instalacja
53
Zadania poinstalacyjne Niezależnie od tego, w jakim systemie operacyjnym pracujemy ani w jaki sposób skonfigurowano serwer WWW, pierwszą czynnością, którą trzeba wykonać po zainstalowaniu języka PHP i uruchomieniu serwera MySQL, jest zdefiniowanie hasła użytkownika root dla systemu MySQL. MySQL pozwala swoim autoryzowanym przewodnikom na przeglądanie i modyfikowanie informacji przechowywanych w bazach danych, dlatego też przede wszystkim należy poinformować MySQL, kto jest takim autoryzowanym użytkownikiem, a kto nie. Po zainstalowaniu system MySQL jest konfigurowany w ten sposób, że ma tylko jednego użytkownika root, który w systemie MySQL posiada dostęp do wszystkiego bez konieczności podawania jakiegokolwiek hasła. Dlatego pierwszym naszym zadaniem powinno być przypisanie użytkownikowi root odpowiedniego hasła, aby nieautoryzowani użytkownicy nie mogli szperać w bazach danych. Dlaczego hasło jest aż tak ważne? Należy pamiętać, że serwer MySQL — tak samo jak serwer WWW — jest dostępny z każdego komputera znajdującego się w tej samej sieci. Jeśli pracujemy na komputerze, który jest podłączony do Internetu, oznacza to — oczywiście w zależności od naszych systemowych zabezpieczeń — że do naszego serwera MySQL może sięgać każdy z użytkowników sieci! Wynika stąd potrzeba jak najszybszego wyboru możliwie trudnego do zgadnięcia hasła!
Aby zdefiniować hasło użytkownika root dla systemu MySQL, można użyć narzędzia mysqladmin udostępnianego wraz z serwerem baz danych. Jeżeli stosowałeś się do instrukcji samodzielnej instalacji serwera MySQL prezentowanych we wcześniejszej części tego rozdziału, program mysqladmin powinien znajdować się już w ścieżce systemu operacyjnego. Oznacza to, że można otworzyć okno Terminal (albo wiersz poleceń w systemie Windows) i wpisać w nim nazwę programu bez konieczności przypominania sobie dokładnej ścieżki dostępu do niego. Najlepiej od razu wykonać tę czynność. Należy otworzyć okno Terminal lub wiersz poleceń i wpisać następujące polecenie24: mysqladmin –u root status
Po naciśnięciu klawisza Enter na ekranie powinien pojawić się wiersz lub dwa z podstawowymi statystykami dotyczącymi serwera MySQL: Uptime: 102261 Threads: 1 Questions: 1 Slow queries: 0 ´1 Open tables: 0 Queries per second avg: 0.0
24
Opens: 15
Flush tables:
Jeżeli używasz systemu Windows i nie czujesz się na siłach, by skorzystać z wiersza poleceń, możesz zajrzeć do mojego artykułu „Kev’s Command Prompt Cheat Sweet” dostępnego pod adresem http://www.sitepoint.com/article/command-prompt-cheat-sheet/
54
PHP i MySQL. Witryna WWW oparta na bazie danych
Jeżeli widzisz na ekranie zupełnie inny komunikat, prawdopodobnie masz do czynienia z jedną z dwóch sytuacji. Pierwsza z nich to komunikat błędu z informacją, że program mysqladmin nie mógł się połączyć z serwerem MySQL: mysqladmin: connect to server at 'localhost' failed error: 'Can't connect to MySQL server on 'localhost' (10061)' Check that mysqld is running on localhost and that the port is 3306. You can check this by doing 'telnet localhost 3306'
Obecność takiego komunikatu zazwyczaj oznacza, że serwer MySQL po prostu nie jest uruchomiony. Jeżeli skonfigurowałeś go w taki sposób, by MySQL był uruchamiany automatycznie w momencie startu systemu operacyjnego, sprawdź jeszcze raz poprawność tej konfiguracji. Jeżeli zazwyczaj uruchamiasz MySQL ręcznie, uruchom go samodzielnie i ponownie spróbuj wykonać wspomniane polecenie. Z drugą możliwością mamy do czynienia wówczas, gdy na komputerze Mac wykorzystany został pakiet MAMP. Wówczas wyświetlony może zostać komunikat błędu o następującej treści: mysqladmin: connect to server at 'localhost' failed error: 'Access denied for user 'root'@'localhost' (using password: NO)'
Ten komunikat błędu oznacza, że dla użytkownika root zdefiniowano już hasło na serwerze MySQL. Okazuje się, że właśnie ze względów bezpieczeństwa MAMP posiada już predefiniowane hasło dla użytkownika root wbudowanego serwera MySQL. Hasłem tym jest jednak po prostu słowo root, dlatego i tak trzeba je zmienić, wykonując instrukcje prezentowane poniżej. Bez względu na to, z którym przypadkiem się zetknąłeś, powinieneś już uruchomić program mysqladmin. Przy jego użyciu można zdefiniować hasło dla użytkownika root na serwerze MySQL: mysqladmin –u root –p password "nowehasło"
Słowo nowehasło należy zastąpić docelowym hasłem, które ma zostać zdefiniowane dla serwera MySQL. Upewnij się, że tego hasła nie zapomnisz, ponieważ jeśli któregoś dnia nie będziesz w stanie przypomnieć sobie hasła użytkownika root, konieczne może być usunięcie całej instalacji serwera MySQL i rozpoczęcie jej od nowa! Jak przekonamy się w rozdziale 10., nawet z takich opałów można wyjść cało, jednak jest to dość uciążliwe. W poniższej ramce możesz zapisać hasło zdefiniowane dla użytkownika root serwera MySQL na wypadek, gdybyś go kiedyś potrzebował. Hasło mojego użytkownika root na serwerze MySQL Hasło użytkownika root: _________________________
Gdy naciśniesz klawisz Enter, będziesz musiał podać aktualne hasło użytkownika root dla serwera MySQL. Wystarczy wówczas ponownie nacisnąć Enter, ponieważ na tym etapie root nie ma jeszcze zdefiniowanego hasła, chyba że zainstalowałeś i skonfigu-
Rozdział 1. ♦ Instalacja
55
rowałeś MySQL na komputerze Mac za pomocą pakietu MAMP — w takim przypadku powinieneś wpisać słowo root, czyli domyślne hasło użytkownika root serwera MySQL z pakietu MAMP. Poniżej prezentowane są poszczególne elementy polecenia, aby łatwiej było zrozumieć jego istotę: mysqladmin
Oczywiście, jest to nazwa programu, który ma zostać uruchomiony. -u root
Element wskazuje konto użytkownika serwera MySQL, za pośrednictwem którego ma zostać nawiązane połączenie z serwerem MySQL. W nowej wersji serwera obecne jest tylko jedno konto użytkownika root. -p
Element wskazuje programowi, że powinien zapytać o aktualne hasło do konta użytkownika. W nowej instalacji serwera MySQL konto użytkownika root nie ma żadnego zdefiniowanego hasła, dlatego gdy serwer zapyta o hasło, wystarczy nacisnąć klawisz Enter. Warto jednak wyrobić sobie nawyk każdorazowego dołączania tego elementu do polecenia, ponieważ w znakomitej większości przypadków trzeba będzie podać hasło, aby połączyć się z serwerem MySQL. password "nowehasło"
Element wskazuje programowi mysqladmin, aby zmienić hasło do konta użytkownika na nowehasło. W naszym przykładzie słowo, którym zastąpione zostanie słowo nowehasło, stanie się nowym hasłem dla użytkownika root na serwerze MySQL. Aby sprawdzić, czy nowe hasło zostało prawidłowo zdefiniowane, należy jeszcze raz nakazać serwerowi MySQL wyświetlenie informacji o jego stanie. W tym celu w wierszu poleceń trzeba dodatkowo użyć opcji –p: mysqladmin –u root –p status
Gdy program o to poprosi, wpisz nowe hasło. Podobnie jak poprzednio, powinieneś ujrzeć na ekranie jeden lub dwa wiersze ze statystykami serwera MySQL. Ponieważ konto użytkownika root jest od teraz chronione hasłem, próba wykonania powyższego polecenia bez opcji –p spowoduje, że zwrócony zostanie błąd „Access Denied”. I to wszystko! Po wykonaniu wszystkich czynności instalacyjnych i konfiguracyjnych możesz przystąpić do napisania swego pierwszego skryptu w języku PHP. Zanim jednak się tym zajmiemy, warto najpierw napisać krótką wiadomość pocztową do dostawcy usług internetowych.
56
PHP i MySQL. Witryna WWW oparta na bazie danych
O co zapytać dostawcę usług internetowych? Gdy zmagasz się z instalacją języka PHP i serwera MySQL na własnym komputerze, warto w międzyczasie zacząć gromadzić informacje, które będą potrzebne w momencie, kiedy przyjdzie do udostępnienia swojej pierwszej bazodanowej witryny internetowej szerokiej publiczności. Poniżej prezentuję listę informacji, o które warto zapytać dostawcę usług internetowych. Na początek trzeba poznać sposób przesyłania plików na serwer internetowy. Skrypty języka PHP przesyła się na serwer w taki sam sposób jak pliki HTML, CSS oraz obrazki składające się na witrynę statyczną. Jeżeli więc już wiesz, jak przesyła się pliki tworzące statyczne witryny internetowe, nie musisz poruszać tej kwestii w korespondencji do dostawcy. Jeżeli jednak zaczynasz współpracę z nowym dostawcą, będziesz musiał się dowiedzieć, z jakiego protokołu transferu plików on korzysta (FTP lub SFTP), a także poprosić o nazwę użytkownika i hasło wymagane do nawiązania połączenia z serwerem za pomocą programu (S)FTP. Musisz także dowiedzieć się, w jakim katalogu powinno się umieścić pliki, aby stały się dostępne dla przeglądarek internetowych. Oprócz tego, warto też uzyskać kilka szczegółowych informacji na temat serwera MySQL, który udostępnia dostawca. Przede wszystkim trzeba poznać nazwę komputera, do którego będziesz musiał się podłączać (prawdopodobnie będzie to localhost), jak również nazwę użytkownika i hasło — być może będą one (choć nie muszą) takie same jak dane logowania do serwera (S)FTP. Dostawca usług internetowych zapewne udostępni od razu pustą bazę danych gotową do użycia, aby uniknąć konfliktów z innymi bazami danych utrzymywanymi przez innych użytkowników na tym samym serwerze MySQL. Jeżeli taka baza jest dostępna, trzeba dowiedzieć się, jaką nosi nazwę. Czy zapamiętałeś wszystko? Poniżej znajduje się tabelka, w której można zapisać informacje pozyskane od dostawcy usług internetowych. Informacje o serwerze internetowym Protokół przesyłania plików: FTP SFTP Nazwa serwera (S)FTP:
_____________________________
Nazwa użytkownika (S)FTP:
_____________________________
Hasło użytkownika (S)FTP:
_____________________________
Nazwa serwera MySQL:
_____________________________
Nazwa użytkownika MySQL:
_____________________________
Hasło użytkownika MySQL:
_____________________________
Nazwa bazy danych MySQL: _____________________________
Rozdział 1. ♦ Instalacja
57
Nasz pierwszy skrypt PHP Postąpiłbym nie fair, gdybym najpierw pokazał czytelnikom, jak wszystko zainstalować, a potem nie dał nawet próbki, jak może wyglądać strona WWW zbudowana z pomocą PHP, nim dotrzemy do rozdziału 3. Oto prosty skrypt, by choć częściowo zaspokoić waszą ciekawość. Otwórzmy więc nasz ulubiony edytor tekstowy lub edytor HTML i utwórzmy plik today.php. Nasz skrypt powinien wyglądać następująco. Listing 1.1. today.php
Dzisiejsza data
Dzisiejsza data (według tego serwera WWW) to
Edycja skryptów PHP w systemie Windows przy użyciu Notatnika Użytkownicy Windows korzystający z edytora Notatnik powinni pamiętać, że aby zachować plik z rozszerzeniem .php, muszą wybrać opcję Wszystkie pliki lub też ujmować nazwę pliku w cudzysłów w oknie dialogowym Zapisz jako. W przeciwnym bowiem razie Notatnik uprzejmie zachowa ten plik pod nazwą todaj.php.txt i skrypt nie będzie działać.
Edycja skryptów PHP w systemie Mac OS X przy użyciu TextEdit Użytkownicy pracujący w systemie Mac OS X nie powinni edytować plików .php w programie TextEdit, ponieważ zachowuje on pliki w uniwersalnym formacie RTF (ang. Rich Text Format), opatrując je niewidocznym rozszerzeniem .rtf. Aby zapisać nowy plik z rozszerzeniem .php, trzeba pamiętać, by najpierw przekształcić zawartość pliku w zwykły tekst przez wybranie w menu narzędzia TextEdit polecenia Format/Make Plain Text (×+a+T). TextEdit ma również brzydki nawyk otwierania plików z rozszerzeniem .php w takim trybie, jakby były to pliki HTML, i wyświetlania ich zawartości w postaci sformatowanego tekstu. Aby tego uniknąć, w oknie dialogowym Open trzeba zaznaczyć pole wyboru Ignore rich text commands.
58
PHP i MySQL. Witryna WWW oparta na bazie danych
Wypróbuj darmowe zintegrowane środowisko programistyczne! Jak wynika z wcześniejszych ostrzeżeń, edytory tekstu dostępne w systemach operacyjnych nie nadają się zbytnio do edytowania skryptów języka PHP. Istnieje jednak wiele rozbudowanych edytorów tekstu oraz zintegrowanych środowisk programistycznych (ang. Integrated Development Environment — IDE) zawierających obsługę skryptów PHP i dostępnych do pobrania za darmo. Poniżej prezentuję kilka tego typu programów, które działają w systemie Windows, Mac OS X i Linux. NetBeans http://www.netbeans.org/features/php/ Aptana http://www.aptana.com/php Komodo Edit http://www.activestate.com/komodo_edit
Jeżeli nie masz ochoty wpisywać ręcznie kodu źródłowego skryptu, możesz pobrać gotowy plik z kodem, który wraz z resztą kodów prezentowanych w tej książce jest dostępny w przygotowanej dla niej witrynie WWW. Więcej informacji na ten temat można znaleźć w przedmowie. Zapisz plik i przenieś go do katalogu dokumentów WWW lokalnego serwera internetowego. Gdzie znajduje się katalog dokumentów WWW? Jeżeli używasz serwera Apache i zainstalowałeś go samodzielnie, wówczas katalogiem dokumentów WWW jest katalog htdocs znajdujący się w katalogu instalacyjnym serwera (czyli C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\ w systemie Windows i /usr/local/apache2/htdocs w systemie Linux). Na serwerze Apache wbudowanym w WampServer katalogiem dokumentów WWW jest katalog o nazwie www, będący podkatalogiem katalogu WampServer. Można go szybko odnaleźć przez wybranie polecenia www directory w menu WampServer, w pasku narzędziowym systemu Windows. Jeżeli używasz serwera Apache wbudowanego w system Mac OS X, katalogiem dokumentów WWW jest katalog /Library/WebServer/Documents. Na serwerze Apache wbudowanym w pakiet MAMP katalogiem dokumentów WWW jest folder htdocs znajdujący się w folderze MAMP (/Applications/MAMP/htdocs). Jeżeli wolisz, by katalogiem dokumentów WWW był inny katalog, możesz to zmienić na zakładce Apache ustawień aplikacji MAMP.
Otwórz wybraną przeglądarkę internetową i w pasku adresu wpisz adres http://localhost/ today.php (albo http://localhost:port/today.php, jeżeli serwer Apache został skonfigurowany w taki sposób, by działał na porcie innym niż domyślny port 80), aby zobaczyć wynik działania skryptu utworzonego przed chwilą25.
25
Jeżeli zainstalowałeś serwer Apache w systemie Windows, być może ustawiłeś go tak, by działał na porcie 8080. Jeżeli używasz pakietu MAMP, Apache został domyślnie skonfigurowany do pracy na porcie 8888.
Rozdział 1. ♦ Instalacja
59
Musisz wpisać adres URL! Być może przyzwyczaiłeś się do przeglądania stron WWW przez dwukrotne kliknięcie ich myszą albo przy użyciu polecenia Plik/Otwórz…. Obydwie funkcje wskazują przeglądarce, aby załadowała plik bezpośrednio z dysku twardego komputera, dlatego zawiodą w przypadku ich zastosowania względem plików PHP. Jak wspomniano już wcześniej, skrypty PHP wymagają, aby serwer WWW najpierw odczytywał i wykonywał kod PHP, a dopiero potem wysyłał do przeglądarki kod HTML. Stanie się tak jednak dopiero wówczas, gdy przeglądarka internetowa wywoła plik z serwera WWW po wpisaniu w niej odpowiedniego adresu URL (http://localhost/ today.php).
Na rysunku 1.30 pokazano, jak powinien wyglądać efekt działania tego skryptu. Rysunek 1.30. Nasz pierwszy skrypt PHP w akcji!
Całkiem nieźle, prawda? Jeśli skorzystamy z opcji podglądu kodu źródłowego (Widok/Źródło) w przeglądarce, zobaczymy po prostu zwykły kod pliku HTML z wstawioną datą. Kod PHP (wszystko, co w przedstawionym skrypcie zawarte było między ) został zinterpretowany przez serwer WWW i przed przesłaniem do przeglądarki przekonwertowany na zwykły tekst. Piękno języka PHP i innych języków skryptowych działających po stronie serwera polega na tym, że przeglądarka internetowa nie musi o nich nic wiedzieć — całą pracę interpretacyjną wykonuje za nią serwer WWW! Nie warto na razie zastanawiać się nad dokładnym sensem kodu prezentowanego w tym przykładzie. Cierpliwości, już niedługo poznacie język PHP od podszewki. Jeśli data nie pojawi się w oknie przeglądarki, oznacza to, że są problemy z obsługą języka PHP w naszym serwerze WWW. W takim przypadku warto skorzystać z opcji podglądu kodu źródłowego w naszej przeglądarce internetowej, żeby przyjrzeć się kodowi źle wyświetlonej strony. Prawdopodobnie tym razem w kodzie strony pojawi się kod PHP. Ponieważ przeglądarka nie rozumie języka PHP, potraktuje kod wewnątrz jak jeden długi, nieprawidłowy znacznik HTML i po prostu go zignoruje. Trzeba więc się upewnić, że rzeczywiście plik został wywołany z serwera WWW, a nie z dysku twardego (inaczej mówiąc, trzeba sprawdzić, czy w pasku adresu przeglądarki znajduje się adres URL rozpoczynający się od http://localhost). Warto również upewnić się, że obsługa języka PHP została poprawnie zainstalowana na naszym serwerze WSW, zgodnie z instrukcjami prezentowanymi wcześniej w tym rozdziale.
60
PHP i MySQL. Witryna WWW oparta na bazie danych
Narzędzia gotowe, pora do pracy Po lekturze tego rozdziału powinieneś już posiadać w pełni funkcjonalny serwer WWW z obsługą języka PHP i serwer baz danych MySQL, a także rozumieć sposób wykorzystania obydwu tych serwerów. Co więcej, napisałeś i przetestowałeś swój pierwszy skrypt PHP! Jeżeli skrypt today.php nie zadziałał prawidłowo, zasięgnij informacji na forum SitePoint Forums26; z przyjemnością pomożemy rozwiązać problem! W rozdziale 2., „Wprowadzenie do systemu MySQL”, poznamy podstawy działania relacyjnych baz danych i zaczniemy korzystać z systemu MySQL. W rozdziale znajdzie się także wprowadzenie do języka baz danych — Structured Query Language. Obiecuję, że rozdział ten będzie znakomitym wprowadzeniem nawet dla osób, które nigdy nie miały żadnego kontaktu z bazami danych!
26
http://www.sitepoint.com/forums/
Rozdział 2.
Wprowadzenie do systemu MySQL W rozdziale 1. zatytułowanym „Instalacja” przyjrzeliśmy się instalowaniu dwóch potrzebnych nam programów, czyli serwera WWW Apache z obsługą języka PHP i serwera zarządzania relacyjnymi bazami danych MySQL. Jak już wspomniano w poprzednim rozdziale, PHP to język skryptowy działający po stronie serwera, umożliwiający wstawianie na strony WWW instrukcji wykonywanych przez nasz serwer WWW (w większości przypadków będzie to serwer Apache) przed przesłaniem tych stron do przeglądarki, która ich zażądała. W prostym przykładzie na końcu rozdziału pokazałem, jak za pomocą PHP wstawiać na stronę WWW aktualną datę. Cóż, wszystko to ładne i przyjemne, ale rzecz robi się naprawdę ciekawa, gdy dodamy do tego bazę danych. W tym rozdziale dowiemy się, czym jest baza danych i jak korzystać z baz danych MySQL, używając języka SQL (ang. Structured Query Launguage, strukturalny język zapytań).
Wprowadzenie do baz danych Serwer bazy danych (w naszym przypadku MySQL) to po prostu program, który potrafi przechowywać wielką ilość informacji w uporządkowanym formacie, tak aby były one łatwo dostępne za pomocą języków programowania, takich jak PHP. Możemy na przykład poinstruować PHP, by zaglądał do bazy danych w poszukiwaniu listy kawałów, które następnie zostaną wyświetlone w naszej witrynie WWW. W prezentowanym przykładzie dowcipy będą przechowywane wyłącznie w bazie danych. Korzyści z zastosowania takiego rozwiązania są dwojakie. Po pierwsze, zamiast tworzyć osobną stronę HTML dla każdego z kawałów, będziemy mogli napisać prosty skrypt PHP, który będzie pobierał odpowiedni dowcip z bazy danych i wyświetlał go na wygenerowanej „w locie” stronie HTML. Po drugie, dodawanie do witryny WWW będzie
62
PHP i MySQL. Witryna WWW oparta na bazie danych
wymagało jedynie wstawienia nowego kawału do bazy danych. Kod PHP zajmie się resztą, automatycznie wyświetlając nowy dowcip wraz z innymi, gdy ich lista będzie pobierana z bazy danych. Przykład ten pomoże zrozumieć, w jaki sposób baza danych przechowuje informacje. Baza danych składa się bowiem z tabel, z których każda przechowuje listę elementów lub rzeczy. W przypadku naszej bazy danych zaczniemy zapewne od tabeli kawal, która zawierać będzie listę kawałów. Każda tabela w bazie danych będzie też posiadać jedną lub więcej kolumn, zwanych czasem polami. Każda kolumna przechowuje określony fragment informacji o każdej z rzeczy przechowywanych w tabeli. W naszym przykładzie tabela kawal może posiadać jedną kolumnę zawierającą teksty poszczególnych kawałów i inną — przechowującą daty wstawienia kawałów do bazy danych. Każdy dowcip przechowywany w ten sposób będzie pojedynczym wierszem (lub inaczej rekordem) tabeli. Wiersze i kolumny tworzą razem tabelę, mniej więcej taką jak na rysunku 2.1. Rysunek 2.1. Struktura typowej tabeli bazy danych zawierającej listę dowcipów
Warto zauważyć, że oprócz kolumn przechowujących tekst kawału (tekstkawalu) i datę wstawienia kawału (datakawalu) dodałem jeszcze kolumnę identyfikatora (id). Jedna bowiem z zasad dobrego projektowania bazy danych głosi, że każda tabela powinna dostarczać jakąś metodę jednoznacznego identyfikowania każdego ze swoich wierszy. Ponieważ może się zdarzyć, że dany kawał zostanie tego samego dnia wprowadzony do bazy danych dwa razy, kolumny tekstkawalu i datakawalu nie wystarczą do rozróżniania poszczególnych dowcipów. Dlatego też funkcją kolumny id jest przypisywanie każdemu kawałowi unikatowego numeru, dzięki czemu zyskamy łatwy sposób odwoływania się do nich i ich identyfikacji. Te i inne zagadnienia związane z projektowaniem baz danych omówione zostaną dokładniej w rozdziale 5., zatytułowanym „Projektowanie relacyjnych baz danych”. Podsumowując, mogę powiedzieć, że tabela zaprezentowana na rysunku 2.1 posiada trzy kolumny oraz dwa wiersze (lub inaczej: dwie pozycje albo dwa rekordy). Każdy wiersz tabeli zawiera trzy pola, po jednym dla każdej z kolumn tabeli: identyfikatora kawału, tekstu kawału i daty wstawienia kawału. Uzbrojeni w tę podstawową terminologię, możemy przystąpić do poznawania systemu MySQL.
Logowanie się na serwerze MySQL Tak jak zadaniem serwera WWW jest odpowiadanie na żądania przesyłane przez klienta (czyli przeglądarkę internetową), tak serwer baz danych MySQL odpowiada na żądania pochodzące z programów klienckich. W dalszej części książki będziemy tworzyć
Rozdział 3. ♦ Wprowadzenie do systemu MySQL
63
własne programy klientów serwera MySQL w postaci skryptów PHP. Na razie jednak możemy używać standardowych programów klienckich stanowiących elementy składowe serwera MySQL. Program mysqladmin jest sztandarowym przykładem programu — klienta serwera MySQL. Jeżeli uważnie wykonywałeś instrukcje zamieszczone w rozdziale 1., po samodzielnym zainstalowaniu serwera MySQL użyłeś programu klienckiego mysqladmin do połączenia się z serwerem, zdefiniowania hasła dla użytkownika root i przeglądania podstawowych statystyk działającego serwera. Kolejnym programem klienckim wchodzącym w skład serwera MySQL jest program mysql. Stanowi on najbardziej podstawowy interfejs do pracy z serwerem MySQL,
ponieważ ustanawia połączenie z serwerem i pozwala na wpisywanie poleceń. Program mysql znajduje się w tym samym miejscu co program mysqladmin, dlatego jeżeli wykonałeś instrukcje przedstawione w rozdziale 1. i dodałeś tę lokalizację do ścieżki systemowej, powinieneś już otworzyć okno Terminal (albo okno wiersza poleceń, jeżeli używasz systemu Windows) i wpisać w nim polecenie uruchamiające program kliencki mysql: mysql --version
Jeżeli wszystko zostało zainstalowane i skonfigurowane prawidłowo, na ekranie powinien zostać wyświetlony wiersz z opisem wersji programu klienckiego mysql wchodzącego w skład zainstalowanego serwera. Na moim komputerze Mac opis ten wygląda następująco: mysql Ver 14.14 Distrib 5.1.31, for apple-darwin9.5.0 (i386) using readline 5.1
Jeżeli natomiast zamiast opisu zwrócony został komunikat o błędzie z informacją, że komputer nie może rozpoznać polecenia mysql, prawdopodobnie powinieneś jeszcze raz wykonać czynności opisane w rozdziale 1. Gdy zyskasz możliwość wykonywania poleceń programu mysqladmin, dostępny powinien być też program mysql. Jeżeli jednak wciąż nie umiesz poradzić sobie z problemem, zajrzyj na stronę SitePoint Forums1 i poproś kogoś o pomoc. Jeżeli program mysql działa prawidłowo, można za jego pomocą połączyć się z serwerem MySQL. Najpierw trzeba się upewnić, że serwer działa, a następnie wpisać poniższe polecenie i nacisnąć klawisz Enter: mysql –u root –p
Parametry –u root i –p mają takie samo znaczenie jak w programie mysqladmin w rozdziale 1. Parametr –u root wskazuje serwerowi, że połączenie ma nastąpić za pośrednictwem konta użytkownika root, natomiast parametr –p oznacza, że użytkownik zamierza podać hasło do tego konta.
1
http://www.sitepoint.com/forums/
64
PHP i MySQL. Witryna WWW oparta na bazie danych
Po naciśnięciu klawisza Enter na ekranie powinna pojawić się prośba o podanie hasła Enter password:. Należy wpisać hasło użytkownika root, które zdefiniowano w rozdziale 1., po czym nacisnąć klawisz Enter. Jeśli polecenie i hasło wpisaliśmy prawidłowo, klient MySQL przedstawi się serwerowi i przerzuci nas bezpośrednio do wiersza poleceń systemu MySQL: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 7 Server version: 5.1.31 MySQL Community Server (GPL) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql>
Wykonajmy kilka prostych poleceń, aby dowiedzieć się czegoś więcej o serwerze MySQL. Serwer MySQL może obsługiwać więcej niż jedną bazę danych. Pozwala to na przykład konfigurować na hostach goszczących strony WWW jeden serwer MySQL, który obsługiwać będzie kilku różnych subskrybentów usługi. Tak więc pierwszym krokiem po nawiązaniu połączenia z serwerem jest wybór bazy danych, z którą chcemy pracować. Najpierw pobierzmy listę baz danych działających na obecnym serwerze. Należy wpisać następujące polecenie (pamiętając o średniku na końcu!) i nacisnąć Enter2: mysql>SHOW DATABASES;
W tym momencie MySQL wyświetli listę baz danych działających na serwerze. Jeśli pracujemy na zupełnie nowym serwerze, lista baz danych powinna wyglądać następująco: +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | test | +--------------------+ 2 rows in set (0.11 sec)
Pierwszą bazę danych, o nazwie information_schema, serwer MySQL wykorzystuje do przechowywania informacji o wszystkich innych bazach danych znajdujących się na serwerze. Jeżeli nie wykonujesz żadnych bardzo zaawansowanych operacji, prawdopodobnie nigdy nie będziesz musiał korzystać z tej bazy. Druga baza danych, o nazwie mysql, również odgrywa wyjątkową rolę. MySQL wykorzystuję ją do przechowywania informacji o użytkownikach, ich hasłach oraz upraw-
2
Podobnie jak w rozdziale 1., symbol zachęty mysql> powinien już być widoczny na ekranie, wystarczy zatem wpisać tylko polecenie, które za nim występuje.
Rozdział 3. ♦ Wprowadzenie do systemu MySQL
65
Nawiązywanie połączenia ze zdalnym serwerem MySQL Instrukcje prezentowane w tym rozdziale dotyczą serwera MySQL działającego na naszym własnym komputerze. Oczywiście, gdy przyjdzie czas na opublikowanie pierwszej witryny WWW zaimplementowanej w PHP i opartej na serwerze MySQL, będziesz musiał wiedzieć, jak korzystać z serwera MySQL udostępnianego przez dostawcę usług internetowych albo przez departament IT firmy, której jesteś pracownikiem. Z technicznego punktu widzenia, program mysql, którego używamy w tym rozdziale, potrafi łączyć się również ze zdalnymi serwerami MySQL. Wystarczy w momencie jego uruchamiania dodać jeszcze jeden parametr: mysql -h nazwa-hosta –u nazwa-użytkownika –p
Parametr –h nazwa-hosta (gdzie nazwa-hosta to nazwa komputera z serwerem MySQL, z którym chcemy się połączyć) wskazuje programowi konkretny, zdalny serwer MySQL zamiast serwera działającego na własnym komputerze. Podanie tego parametru spowoduje prawdopodobnie, że konieczne będzie także podanie nazwy użytkownika innej niż root, ponieważ ze względów bezpieczeństwa administratorzy opiekujący się serwerem MySQL nie udostępnią hasła tego użytkownika nikomu z zewnątrz. W praktyce na większości serwerów MySQL połączenia od klientów działających na komputerach, które nie są zaufane, czyli również na naszym komputerze, będą blokowane. Odrzucanie tego rodzaju połączeń jest standardowym zabezpieczeniem serwerów MySQL działających w środowisku produkcyjnym. Aby zacząć korzystać ze zdalnego serwera MySQL, być może będziesz musiał najpierw połączyć się z zaufanym komputerem i dopiero na nim uruchomić program mysql. Znacznie częściej spotykanym rozwiązaniem jest jednak użycie programu o nazwie phpMyAdmin do zarządzania zdalnymi bazami danych. Program phpMyAdmin to rozbudowany skrypt PHP, który służy do pracy na bazach danych MySQL przy użyciu interfejsu internetowego dostępnego przez przeglądarkę. Program phpMyAdmin łączy się ze zdalnym serwerem MySQL w takim sam sposób jak skrypty PHP, które będziemy pisać w tej książce. Sposób instalacji i pracy z phpMyAdmin zostanie opisany w rozdziale 10. Na razie skupimy się na poznaniu sposobów korzystania z serwera MySQL zainstalowanego na własnym komputerze.
nieniach (o tym, co im wolno w bazie danych). Na razie nie podejmujemy tej kwestii, niemniej powrócimy do niej jeszcze w rozdziale 10., w którym omówimy dokładniej zasady administrowania systemem MySQL. Trzecia baza danych, o nazwie test, to przykładowa baza danych przygotowana przez twórców systemu MySQL. Prawdę powiedziawszy, możemy ją nawet usunąć z systemu, ponieważ za chwilę pokażę, jak samodzielnie tworzy się własne bazy danych. Na serwerze WampServer baza test nie występuje W wersji serwera WampServer dostępnej w trakcie powstawania tej książki zbiór początkowych baz danych serwera MySQL nie zawierał bazy test. Nie ma jednak powodów do obaw — twórcy serwera WampServer, tak jak ja, doszli zapewne do wniosku, że baza ta nie jest potrzebna.
66
PHP i MySQL. Witryna WWW oparta na bazie danych
Nazwa polecenia służącego do usuwania czegokolwiek, czego chcielibyśmy się pozbyć z bazy danych MySQL, jest zawsze taka sama i pochodzi od angielskiego słowa drop (porzucać): mysql>DROP DATABASE test;
Jeśli wpiszemy to polecenie i naciśniemy Enter, system MySQL posłusznie usunie bazę danych, wyświetlając potwierdzający komunikat „Query OK”. Warto zauważyć, że nie pojawia się żadna prośba o potwierdzenie w rodzaju: „Are you sure?” Należy więc zachować wielką ostrożność podczas wpisywania poleceń w programie klienckim mysql, ponieważ — jak widać w powyższym przykładzie — za pomocą jednego polecenia można wymazać całą bazę danych, wraz z wszystkimi zawartymi w niej informacjami! Zanim przejdziemy do dalszych wywodów, warto dowiedzieć się czegoś więcej o wierszu poleceń MySQL. Jak uważni czytelnicy zapewne dostrzegli, wszystkie polecenia wpisywane w systemie MySQL muszą być zakończone średnikiem (;). Jeśli zapomnimy o średniku, system MySQL nie będzie wiedział, że zakończyliśmy wpisywanie polecenia i pozwoli nam kontynuować je w następnym wierszu: mysql>SHOW ->DATABASES;
MySQL sygnalizuje, że czeka na dalszą część polecenia, zmieniając znak gotowości z mysql> na ->. Takie rozwiązanie pozwala na zapisywanie rozbudowanych poleceń w kilku wierszach. Wielkość liter w poleceniach języka SQL W większości poleceń serwera MySQL wielkość liter nie ma znaczenia, co oznacza, że polecenia SHOW DATABASES, show databases i ShOw DaTaBaSeS są równoważne. Jednak wielkość liter w nazwach tabel i baz danych nabiera znaczenia wówczas, gdy serwer MySQL działa w systemie operacyjnym z systemem plików rozróżniającym wielkość znaków (takim jak Linux albo Mac OS X, zależnie od konfiguracji używanego systemu). Ponadto nazwy tabel, kolumn i inne muszą być zapisywane w identyczny sposób, gdy są używane w tym samym poleceniu więcej niż jeden raz. W celu zachowania spójności w książce będziemy stosować się do powszechnie przyjętej konwencji zapisywania poleceń baz danych wielkimi literami oraz wskazywania elementów bazy danych (nazw baz danych, tabel, kolumn i im podobnych) małymi literami.
Jeśli w trakcie wpisywania polecenia zorientujemy się, że gdzieś po drodze popełniliśmy błąd, możemy anulować bieżące polecenie i zacząć od początku. W tym celu należy wpisać \c i nacisnąć Enter: mysql>DROP DATABASE\c mysql>
System MySQL zignoruje anulowane w ten sposób polecenie i wyświetli znak gotowości mysql>, sygnalizując, że czeka na kolejne polecenie.
Rozdział 3. ♦ Wprowadzenie do systemu MySQL
67
Na koniec wreszcie, aby wyjść z programu klienta MySQL, wystarczy wpisać quit lub exit (obie wersje polecenia będą działać). Jest to jedyne polecenie, które nie musi być zakończone średnikiem, niemniej możemy go dodać na końcu, jeśli nam na tym zależy. mysql>quit Bye
SQL — Strukturalny Język Zapytań Zestaw poleceń, którego będziemy dalej używać, by kierować systemem MySQL, to polecenia strukturalnego języka zapytań SQL (czyt. „eskuel” lub żartobliwie „sequel” — do wyboru). Polecenia języka SQL nazywa się zazwyczaj zapytaniami (ang. queries). W dalszej części książki oba te terminy będą używane wymiennie. SQL jest standardowym językiem wykorzystywanym do komunikacji z większością baz danych, dlatego nawet jeśli spróbujemy w przyszłości przenieść bazę zbudowaną w systemie MySQL do innego systemu, na przykład Microsoft MySQL Server, większość poleceń, których będziemy tam używać, będzie identyczna. Najważniejszą na razie kwestią jest zrozumienie, na czym polega różnica między SQL a MySQL. MySQL to specjalny program serwera bazy danych, na którym będziemy pracowali. SQL z kolei to specjalny język służący do komunikowania się z bazami danych. Nauka języka SQL na poziomie zaawansowanym W książce przedstawione zostaną podstawy języka SQL, które powinien znać każdy programista PHP. Jeżeli zdecydujesz się poświęcić tworzeniu witryn WWW opartych na bazach danych, szybko dojdziesz do wniosku, że niezbędne jest poznanie bardziej zaawansowanych aspektów języka SQL zwłaszcza po to, aby tworzyć witryny jak najszybciej i jak najbardziej skutecznie. Jeżeli chcesz lepiej poznać tajniki języka SQL, gorąco polecam książkę Head First SQL. 3 Edycja polska autorstwa Lynn Beighley (Wydawnictwo Helion, 2009).
Tworzenie bazy danych Gdy przyjdzie do wdrożenia w sieci Internet naszej pierwszej witryny WWW opartej na bazie danych, prawdopodobnie od razu zauważysz, że dostawca usług internetowych lub departament IT firmy już stworzył bazę danych MySQL przeznaczoną dla tej witryny. Ponieważ jednak sam odpowiadasz za własny serwer MySQL, samodzielnie musisz utworzyć bazę danych potrzebną w trakcie procesu tworzenia witryny.
3
http://helion.pl/ksiazki/hfsql.htm
68
PHP i MySQL. Witryna WWW oparta na bazie danych
Bazę danych tworzy się prawie tak samo prosto jak usuwa: mysql>CREATE DATABASE ijdb;
Dziwaczna nazwa bazy danych ijdb jest skrótem od angielskich słów Internet Joke Database4 (internetowa baza kawałów), ponieważ jej właśnie będziemy używać w naszych przykładach wspomnianych na początku tego rozdziału, czyli na internetowej witrynie wyświetlającej bazę danych dowcipów. Oczywiście, w dziedzinie nazewnictwa własnych baz danych obowiązuje dowolność. Gdy już będziemy mieli bazę danych, musimy poinformować system MySQL, że chcemy jej używać. I tym razem polecenie służące do tego celu nie jest zbyt trudne do zapamiętania: mysql>USE ijdb;
Od tego momentu można swobodnie używać naszej bazy danych. Ponieważ dopóki nie wstawimy do niej paru tabel, dopóty nasza baza danych będzie pusta, naszym pierwszym zadaniem będzie przygotowanie tabeli, która przechowa nasze kawały (jest to dobry moment, by zacząć sobie przypominać jakieś dowcipy!).
Tworzenie tabel Polecenia SQL, z którymi mieliśmy do czynienia do tej pory, były dość proste. Niemniej tabele bazy danych oferują tyle możliwości, że siłą rzeczy polecenie je tworzące musi być bardziej skomplikowane. Oto podstawowa składnia tego polecenia: mysql>CREATE TABLE nazwa_tabeli ( -> nazwa_kolumny_1 typ_kolumny_1 szczegóły_kolumny_1, -> nazwa_kolumny_2 typ_kolumny_2 szczegóły_kolumny_2, -> ... ->) DEFAULT CHARACTER SET zestaw_znaków;
Wróćmy teraz do naszego przykładu tabeli kawałów przedstawionego na rysunku 2.1. Jak pamiętamy, ma ona trzy kolumny: id (liczba), tekstkawalu (tekst kawału) i datakawalu (data dodania kawału do bazy). Polecenie tworzące tę tabelę będzie więc następujące: mysql>CREATE TABLE kawal ( -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -> tekstkawalu TEXT, -> datakawalu DATE NOT NULL ->) DEFAULT CHARACTER SET utf8;
Dość przerażające, prawda? Spróbujmy je zatem zanalizować. CREATE TABLE kawal (
Pierwszy wiersz jest dość prosty. Oznacza, że zamierzamy utworzyć nową tabelę o nazwie kawal. Nawias otwierający (() wskazuje początek listy kolumn, jakie ma zawierać tabela. 4
Na wzór witryny Internet Movie Database (http://www.imdb.com).
Rozdział 3. ♦ Wprowadzenie do systemu MySQL
69
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Drugi wiersz informuje o tym, że chcemy mieć w niej kolumnę o nazwie id, zawierającą liczby całkowite (INT), czyli po prostu pełne liczby. Dalej mamy bardziej szczegółowe informacje na temat kolumny. 1. Gdy tworzony będzie nowy wiersz w tabeli, kolumna ta nie może pozostać pusta, to jest musi zawierać jakąś wartość (NOT NULL). 2. Następnie chcielibyśmy, by MySQL automatycznie wybierał dla nas wartość tej kolumny — liczbę o jeden większą (AUTO_INCREMENT) niż
najwyższa z dotychczasowych wartości w tej kolumnie tabeli — jeśli sami nie podamy wartości identyfikatora. 3. Na koniec określamy, że kolumna powinna pełnić funkcję unikatowego
(to jest niepowtarzalnego) identyfikatora dla rekordów przechowywanych w tabeli, by każda wartość w tej kolumnie była inna (PRIMARY KEY). tekstkawalu TEXT,
Trzeci wiersz jest bardzo prosty. Informuje, że chcemy utworzyć kolumnę o nazwie tekstkawalu, która zawierać będzie tekst (TEXT). datakawalu DATE NOT NULL
Czwarty wiersz polecenia definiuje wreszcie naszą ostatnią kolumnę, nazwaną datakawalu, która będzie zawierać dane typu DATE (data); ona również nie może być pusta (NOT NULL). ) DEFAULT CHARACTER SET utf8;
Nawias zamykający ()) wskazuje koniec listy kolumn znajdujących się w tabeli. DEFAULT CHARACTER SET utf8 to instrukcja wskazująca serwerowi MySQL,
że w tabeli przechowywany będzie tekst zakodowany w formacie UTF-8. UTF-8 jest najczęściej używanym formatem kodowania treści publikowanych w Internecie, dlatego warto go używać we wszystkich tabelach baz danych, które będą wykorzystywane przez aplikacje WWW. Znajdujący się na końcu instrukcji znak średnika wskazuje programowi klienckiemu mysql, że w tym miejscu kończy się całe zapytanie. Warto również zwrócić uwagę, że definiowaliśmy typ danych dla każdej tworzonej kolumny. Kolumna id przechowywać będzie liczby całkowite, kolumna tekstkawalu — tekst, a kolumna datakawalu — daty. MySQL wymaga podawania z góry typu danych dla każdej z kolumn. Pomaga to nie tylko organizować dane, ale także, jak się przekonamy, porównywać na wiele użytecznych sposobów wartości przechowywane w kolumnach. Pełną listę typów danych obsługiwanych przez MySQL można znaleźć w dodatku C, „Typy danych dla kolumn tabel MySQL”. Jeśli wpisaliśmy zapytanie prawidłowo, MySQL odpowie komunikatem „Query OK” i nasza pierwsza tabela zostanie utworzona. Jeśli popełnimy błąd przy wpisywaniu, system MySQL poinformuje, że jest jakiś problem z zapytaniem i spróbuje wskazać, który fragment polecenia był dla niego niezrozumiały.
70
PHP i MySQL. Witryna WWW oparta na bazie danych
Jednak w przypadku tak złożonego polecenia komunikat „Query OK” nie byłby zbyt ciekawą odpowiedzią, prawda? Przyjrzyjmy się naszej nowej tabeli, by upewnić się, czy została utworzona prawidłowo. W tym celu należy wpisać następujące polecenie: mysql>SHOW TABLES;
Odpowiedź serwera powinna być następująca: +----------------+ | Tables_in_ijdb | +----------------+ | kawal | +----------------+ 1 row in set (0.02 sec)
Jest to lista wszystkich tabel w naszej bazie danych (którą nazwaliśmy wcześniej ijdb). Zawiera tylko jedną tabelę kawal, którą właśnie utworzyliśmy. Przyjrzyjmy się jej bliżej przy użyciu polecenia DESCRIBE: mysql>DESCRIBE kawal; +-------------+---------+------+-----+------------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------+------+-----+------------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | tekstkawalu | text | YES | | NULL | | | datakawalu | date | NO | | NULL | | +-------------+---------+------+-----+------------+----------------+ 3 rows in set (0.10 sec)
Tabela ma zatem trzy kolumny (lub inaczej pola), które tutaj podawane są jako trzy kolejne wiersze tabeli opisującej naszą tabelę. Szczegółowe informacje są na pierwszy rzut oka tajemnicze, niemniej po dokładniejszej analizie łatwo domyślić się, co właściwie znaczą. Na razie jednak nie warto się nimi zbytnio zajmować. Mamy ciekawsze zadania, takie jak na przykład dodawanie kawałów do naszej tabeli! Zanim jednak do tego przystąpimy, warto przyjrzeć się jeszcze jednej ważnej czynności: usuwaniu tabeli. Jest ona tak samo dziecinnie łatwa jak usuwanie bazy danych. Polecenie jest prawie identyczne. Nie wykonuj tego polecenia na tabeli kawal, chyba że jesteś całkowicie pewien, że chcesz się jej pozbyć! mysql>DROP TABLE nazwaTabeli;
Wstawianie danych do tabeli Utworzyliśmy więc już bazę danych i zbudowaliśmy potrzebną nam tabelę; pozostało nam jedynie dodanie do tabeli odpowiednich kawałów. Polecenie, które wstawia dane do bazy, nazywa się ni mniej ni więcej INSERT, co po angielsku znaczy „wstaw”. Polecenie może przyjmować dwa podstawowe warianty: mysql>INSERT INTO nazwa_tabeli SET -> nazwaKolumny1 = wartość1, -> nazwaKolumny2 = wartość2,
Rozdział 3. ♦ Wprowadzenie do systemu MySQL
71
-> ... ->; mysql>INSERT INTO nazwa_tabeli -> (nazwaKolumny1, nazwaKolumny2, ...) -> VALUES (wartość1, wartość2, ...);
Aby więc dodać kawały do naszej tabeli, możemy użyć jednego z dwóch poleceń: mysql>INSERT INTO kawal SET ->tekstkawalu = "Czemu kurczak przebiegł przez drogę? żeby dostać się "> na drugą stronę!", ->datakawalu = "2009-04-01"; mysql>INSERT INTO kawal ->(tekstkawalu, datakawalu) VALUES ( ->"Czemu kurczak przebiegł przez drogę? żeby dostać się na drugą "> stronę!", ->"2009-04-01" ->);
Warto zwrócić uwagę, że w obu wariantach polecenia INSERT porządek, w jakim wyświetlamy kolumny, musi się zgadzać z kolejnością, w jakiej podajemy wartości. Poza tym zastrzeżeniem porządek kolumn nie ma znaczenia. W trakcie wpisywania polecenia zapewne zwróciłeś uwagę, że początek i koniec tekstu dowcipu oznaczyliśmy znakiem cudzysłowu ("). Fragment tekstu zamknięty w cudzysłowach to tak zwany tekstowy ciąg znaków (ang. text string) i w taki właśnie sposób w języku SQL oznacza się większość wartości. Można na przykład zauważyć, że daty również zostały podane jako tekstowe ciągi znaków w postaci "RRRR-MM-DD". Zamiast cudzysłowów (") można zamiennie stosować znaki apostrofów ('): mysql>INSERT INTO kawal ->(tekstkawalu, datakawalu) VALUES ( ->'Czemu kurczak przebiegł przez drogę? żeby dostać się na drugą "> stronę!', ->'2009-04-01';
Powstaje od razu pytanie, jak postąpić w sytuacji, gdy tekst dowcipu również będzie zawierać apostrofy. W takim przypadku najprościej zawrzeć tekst w cudzysłowach i odwrotnie: jeżeli tekst zawiera cudzysłowy, najlepiej umieścić go w apostrofach. Jeżeli z kolei tekst, który ma zostać zapisany w tabeli, zawiera cudzysłowy i apostrofy, konieczne będzie unieważnienie (ang. escape) w tekstowym ciągu znaków tych znaków, które mogą spowodować konflikt. W poleceniach języka SQL znaki unieważnia się przez poprzedzenie ich znakiem odwrotnego ukośnika (\). W ten sposób serwer MySQL otrzymuje wskazówkę, aby zignorować wszelkie „specjalne znaczenia”, jakie ewentualnie może posiadać dany znak. W przypadku apostrofów i cudzysłowów znak odwrotnego ukośnika będzie dla serwera MySQL oznaczał, że nie należy apostrofu (cudzysłowu) interpretować jako znaku zakończenia tekstowego ciągu znaków. Aby unaocznić ten przykład, poniżej prezentuję polecenie INSERT, które wstawia do tabeli angielskojęzyczny tekst dowcipu zawierający zarówno apostrofy, jak i cudzysłowy:
72
PHP i MySQL. Witryna WWW oparta na bazie danych mysql>INSERT INTO kawal ->(tekstkawalu, datakawalu) VALUES ( ->'Knock-knock! Who\'s there? Boo! "Boo" who? '> Don\'t cry; it\'s only a joke!', ->"2009-04-01";
Jak widać, znakiem początku i końca tekstowego ciągu znaków jest apostrof. Z tego powodu musiałem unieważnić trzy apostrofy znajdujące się w tekście dowcipu przez poprzedzenie ich znakiem odwrotnego ukośnika. Dzięki obecności odwrotnych ukośników MySQL wie, że apostrofy powinien potraktować jak zwykłe znaki ciągu, które nie oznaczają jego zakończenia. Jeżeli jesteś szczególnie dociekliwy, zastanawiasz się pewnie, jak zatem zawrzeć w tekstowym ciągu znaków języka SQL znak odwrotnego ukośnika. Otóż w tym celu trzeba po prostu wpisać dwa odwrotne ukośniki (\\) — dzięki temu MySQL potraktuje je jak jeden ukośnik odwrotny wchodzący w skład tekstowego ciągu znaków. Wiemy już, jak dodawać kolejne wiersze do tabeli, zatem czas zobaczyć, jak je przeglądać.
Przeglądanie danych przechowywanych w bazie Polecenie SELECT, którego używamy, by oglądać dane przechowywane w tabelach bazy danych, należy do najbardziej skomplikowanych poleceń w języku SQL. Złożoność ta wynika z tego, że podstawową zaletą baz danych jest ich elastyczność, jeśli chodzi o możliwości pobierania danych. Na tym dość początkowym etapie naszej znajomości z bazami danych będziemy potrzebować tylko dość nieskomplikowanej listy wyników, dlatego też skorzystamy tutaj z najprostszej postaci polecenia SELECT. Polecenie to wyświetli całą zawartość tabeli kawal: mysql>SELECT * FROM kawal;
Zapytanie to oznacza: „pobierz wszystko z tabeli kawal”. Jeśli wpiszemy to polecenie, otrzymamy mniej więcej taki wynik: +----+---------------------------------------------------------------------+------------+ | id | tekstkawalu | datakawalu | +----+---------------------------------------------------------------------+------------+ | 1 | Czemu kurczak przebiegł przez drogę? Żeby dostać się na drugą stronę! | 2009-04-01 | +----+---------------------------------------------------------------------+------------+ 1 row in set (0.05 sec)
Rozdział 3. ♦ Wprowadzenie do systemu MySQL
73
Wynik sprawia wrażenie trochę nieuporządkowanego, ponieważ tekst kawału w kolumnie tekstkawalu jest tak długi, że tabela nie wpasowuje się dobrze w rozmiar ekranu. Można temu zaradzić, informując serwer MySQL, by nie wyświetlał kolumny tekst ´kawalu. Polecenie, które mu to nakazuje, jest następujące: mysql>SELECT id, datakawalu FROM kawal;
Tym razem, zamiast informować go, by „pobrał wszystko”, wskazujemy precyzyjnie, na których kolumnach nam zależy. Wynik zapytania będzie wyglądać tak: +----+------------+ | id | datakawalu | +----+------------+ | 1 | 2009-04-01 | +----+------------+ 1 row in set (0.00 sec)
Całkiem nieźle, ale dobrze by było zobaczyć choć fragment tekstu kawału, prawda? Podobnie jak mogliśmy wymienić określone kolumny, które polecenie SELECT powinno dla nas wyświetlić, możemy też skorzystać z odpowiednich funkcji modyfikujących to, co ukaże się w każdej kolumnie. Jedna z tych funkcji, o nazwie LEFT, umożliwia poinformowanie serwera MySQL, by wyświetlał tylko określoną liczbę początkowych znaków zapisanych w kolumnie. Załóżmy, że chcemy zobaczyć tylko 20 pierwszych znaków kawałów z kolumny tekstkawalu. Oto polecenie, z którego skorzystamy: mysql>SELECT id, LEFT(tekstkawalu, 20), datakawalu FROM kawal; +----+-----------------------+------------+ | id | LEFT(tekstkawalu, 20) | datakawalu | +----+-----------------------+------------+ | 1 | Czemu kurczak przeb | 2009-04-01 | +----+-----------------------+------------+ 1 row in set (0.05 sec)
Wiecie już zatem, jak to działa? Kolejna użyteczna funkcja to COUNT, pozwalająca zliczać liczbę zwracanych wyników. Jeśli na przykład chcemy dowiedzieć się, ile kawałów przechowywanych jest w naszej tabeli, możemy skorzystać z następującego polecenia: mysql>SELECT COUNT(*) FROM kawal; +----------+ | COUNT(*) | +----------+ | 1 | +----------+ 1 row in set (0.06 sec)
Jak widać, w tej chwili mamy w tabeli tylko jeden kawał. Do tej pory w każdym przykładzie pobieraliśmy wszystkie pozycje (rekordy) znajdujące się w tabeli. Gdybyśmy mieli ich więcej, moglibyśmy ograniczyć pobieranie rekordów tylko do tych pozycji, które posiadają odpowiednie atrybuty. Do definiowania tych ograniczeń służy klauzula WHERE polecenia SELECT. Rozważmy następujący przykład: mysql>SELECT COUNT(*) FROM kawal WHERE datakawalu >= "2009-01-01";
74
PHP i MySQL. Witryna WWW oparta na bazie danych
Zapytanie to zwróci tylko te kawały, które mają datę wstawienia późniejszą niż 1 stycznia 2009 roku. W przypadku dat znak „większy lub równy” oznacza „tego dnia lub po nim”. Kolejną wariacją na ten temat może być poszukiwanie rekordów, które zawierać będą określony fragment tekstu. Przyjrzyjmy się następującemu zapytaniu: mysql>SELECT tekstkawalu FROM kawal WHERE tekstkawalu LIKE "%kurczak%";
To zapytanie z kolei wyświetli pełen tekst wszystkich kawałów, które w kolumnie tekstkawalu zawierają tekst „kurczak”. Słowo kluczowe LIKE informuje MySQL, że wymieniona w zapytaniu kolumna musi pasować do podanego wzorca. W tym przypadku wzorzec, którego użyliśmy, to "%kurczak%". Znaki procentu (%) informują system, że zarówno przed, jak i po tekście „kurczak” może pojawić się jakiś tekst. W klauzuli WHERE można jeszcze bardziej ograniczyć rezultaty. Aby na przykład wyświetlić tylko kawały z serii „Puk, puk! Kto tam?” z kwietnia 2009 roku, powinniśmy użyć następującego zapytania: mysql>SELECT tekstkawalu FROM kawal WHERE ->tekstkawalu LIKE "%puk%" AND ->datakawalu >= "2009-04-01" AND ->datakawalu < "2009-05-01";
Polecam wprowadzenie do tabeli jeszcze kilku kawałów i dalszą zabawę z instrukcjami SELECT. Dobra znajomość instrukcji SELECT przyda się bowiem bardzo w dalszej części tej książki. Za pomocą instrukcji SELECT można robić wiele różnych, ciekawych rzeczy. Niektóre z bardziej zaawansowanych zastosowań tej funkcji omówimy w dalszej części książki, w miarę jak będą potrzebne.
Modyfikowanie danych przechowywanych w bazie Gdy już wprowadzimy do tabeli jakieś dane, czasem zachodzi konieczność ich modyfikacji. Chcemy na przykład poprawić literówkę w tekście kawału lub zmienić przypisaną do niego datę. Do tego celu służy polecenie UPDATE. Polecenie to zawiera elementy polecenia SELECT i INSERT, ponieważ odczytuje ono rekordy z tabeli, by je zmodyfikować, oraz definiuje wartości w kolumnach. Podstawowa składnia polecenia UPDATE jest następująca: mysql>UPDATE nazwa_tabeli SET -> nazwa_kolumny = nowa_wartość, ... ->WHERE warunki;
Jeśli więc chcemy zmienić datę dla wpisanego wcześniej kawału, powinniśmy skorzystać z następującego polecenia: mysql>UPDATE kawal SET datakawalu="2010-04-01" WHERE id="1";
Rozdział 3. ♦ Wprowadzenie do systemu MySQL
75
Rozumiemy już więc, na czym polega przydatność kolumny identyfikatora id: umożliwia ona wprowadzenie zmian w jednym, konkretnym kawale. Klauzula WHERE działa tutaj tak samo jak w poleceniu SELECT. Kolejne przykładowe polecenie zmienia daty wszystkich rekordów, które w tekście kawału zawierają słowo „kurczak”: mysql>UPDATE kawal SET datakawalu="2010-04-01" ->WHERE tekstkawalu LIKE "%kurczak%";
Usuwanie danych przechowywanych w bazie Usuwanie rekordów tabel jest w języku SQL — na co już nie pierwszy raz zwracam uwagę — niebezpiecznie proste. Oto składnia polecenia: mysql>DELETE FROM nazwa_tabeli WHERE warunki;
Aby usunąć z naszej tabeli wszystkie kawały ze słowem „kurczak”, należy skorzystać z następującego zapytania: mysql>DELETE FROM kawal WHERE tekstkawalu LIKE "%kurczak%";
Ostrożnie z klawiszem Enter! Trudno w to uwierzyć, ale obecność klauzuli WHERE w zapytaniu DELETE jest opcjonalna. Z tego powodu przy wykonywaniu polecenia DELETE należy zachować ostrożność. Jeżeli w poleceniu nie zostanie zastosowana klauzula WHERE, polecenie DELETE usunie wszystkie pozycje przechowywane w tabeli. Takie polecenie opróżni za jednym zamachem całą tabelę kawal: mysql>DELETE FROM kawal;
Przerażające, prawda?
Niech PHP sam napisze kod SQL O serwerze MySQL i języku SQL można by opowiadać jeszcze długo, nie ograniczając się do tych kilku podstawowych poleceń, który przedstawiłem tutaj. Polecenia, które omówiłem, należą jednak do najczęściej używanych. Obecnie może się wydawać, że bazy danych nie są specjalnie intrygującym narzędziem. Same polecenia języka SQL wpisuje się dość opornie, ponieważ są zwykle długie, wręcz rozwlekłe, w porównaniu z poleceniami i instrukcjami innych języków programowania. Pewnie zniechęcić może już sama myśl o wpisywaniu pełnej biblioteki dowcipów za pomocą instrukcji INSERT.
76
PHP i MySQL. Witryna WWW oparta na bazie danych
Jednak nie ma powodów do obaw! Czytając książkę, będziesz coraz bardziej zaskoczony, jak niewiele zapytań SQL trzeba wpisywać ręcznie. Generalnie będziemy raczej pisać skrypty PHP, które będą generować odpowiednie zapytania SQL. Aby na przykład wstawić do bazy danych zbiór dowcipów, najprościej utworzyć skrypt PHP, który będzie dodawał dowcipy poleceniem INSERT z zarezerwowanym miejscem na właściwy tekst dowcipu. Skrypt taki można potem uruchamiać za każdym razem, gdy trzeba będzie dodać kolejny dowcip. Skrypt PHP poprosi o wpisanie treści dowcipu, a następnie wykona odpowiednie zapytanie INSERT na serwerze MySQL. Obecnie najważniejsze jest jednak, byś przyzwyczaił się do ręcznego wpisywania poleceń języka SQL. Dzięki temu można szybko zorientować się w sposobie działania wewnętrznych mechanizmów baz danych serwera MySQL, a poza tym docenisz PHP za to, jak wiele pracy pomaga uniknąć! Na razie pracowaliśmy tylko z pojedynczą tabelą; aby w pełni docenić możliwości relacyjnej bazy danych, warto również nauczyć się, jak łączyć ze sobą wiele tabel, by tworzyć potencjalnie nawet bardzo złożone relacje między danymi przechowywanymi w bazie. Zajmiemy się tym zagadnieniem dokładniej w rozdziale 5., zatytułowanym „Projektowanie relacyjnych baz danych”, w którym omówimy podstawowe zasady projektowania baz danych i przyjrzymy się przykładom bardziej zaawansowanych zapytań. Na razie jednak osiągnęliśmy nasz cel, którym było nauczenie się, jak komunikować się z serwerem MySQL za pośrednictwem programu klienckiego mysql. Rozdział 3., „Wprowadzenie do języka PHP”, będzie jeszcze ciekawszy, ponieważ zapoznamy się tam z językiem skryptowym PHP i dowiemy się, jak za jego pomocą tworzyć dynamiczne strony WWW. Ci z czytelników, którzy sądzą, że jeszcze brak im wprawy, mogą trochę poćwiczyć na systemie MySQL, zanim rozbudujemy naszą bazę kawałów. Wiedza ta przyda się później w rozdziale 4., „Publikowanie w sieci WWW danych przechowywanych w bazie MySQL”.
Rozdział 3.
Wprowadzenie do języka PHP Język PHP jest językiem działającym po stronie serwera. Rozwiązanie to może nie być oczywiste, szczególnie dla osób przyzwyczajonych do projektowania stron WWW za pomocą języka HTML, arkuszy CSS i języka JavaScript. Język skryptowy działający po stronie serwera jest podobny do JavaScriptu pod tym względem, że umożliwia osadzanie programów (skryptów) w kodzie HTML na stronie WWW. Programy te pozwalają na większą elastyczność w określaniu, co ma się pojawić w oknie przeglądarki, niż byłoby to możliwe za pomocą zwykłego kodu HTML. Podstawowa różnica między JavaScriptem a językiem PHP sprowadza się do tego, w którym momencie ładowania strony WWW dany program jest wykonywany. Kod języków działających po stronie klienta, takich jak JavaScript, jest wykonywany przez przeglądarkę internetową, gdy strona WWW (wraz z osadzonym programem) zostanie załadowana z serwera WWW na komputer użytkownika. Natomiast w przypadku języków działających po stronie serwera, takich jak PHP, skrypty są wykonywane przez serwer WWW, zanim strona zostanie przesłana do przeglądarki. Języki działające po stronie klienta pozwalają kontrolować sposób, w jaki strona zostanie wyświetlona w przeglądarce, z kolei języki działające po stronie serwera służą do generowania odpowiednio skonstruowanych stron „w locie”, jeszcze zanim zostaną one wysłane do przeglądarki. Gdy serwer WWW wykona kod PHP osadzony na stronie, wyniki wykonania tego kodu zastąpią na stronie sam kod PHP. Strona, która dotrze do przeglądarki, zawiera już tylko standardowy kod HTML. Stąd właśnie pochodzi nazwa: język działający po stronie serwera. Wróćmy do przykładowego skryptu today.php, prezentowanego w rozdziale 1. Listing 3.1. today.php
78
PHP i MySQL. Witryna WWW oparta na bazie danych
Dzisiejsza data
Dzisiejsza data (według tego serwera WWW) to
Większość tego skryptu to zwykły kod HTML, niemniej wiersze pomiędzy wskazuje koniec osadzonego kodu PHP. Zadaniem serwera WWW jest zinterpretowanie wszystkiego, co znajdzie między tymi ogranicznikami i przekształcenie na zwykły kod HTML, zanim prześle stronę przeglądarce internetowej. Przeglądarka otrzymuje więc następujący kod:
Dzisiejsza data
Dzisiejsza data (według tego serwera WWW) to Sunday, December 06th 2009.
Warto zauważyć, że w kodzie PHP znikły wszystkie znaki. W ich miejsce pojawia się wynik działania skryptu, który wygląda jak standardowy kod HTML. Przykład ten dobrze ilustruje podstawowe zalety skryptów interpretowanych po stronie serwera. Oto one.
Nie ma problemów z kompatybilnością przeglądarek Skrypty PHP są interpretowane przez sam serwer WWW, więc nie musimy się przejmować, czy język, w którym je piszemy, jest obsługiwany przez przeglądarki internetowe osób odwiedzających stronę.
Mamy dostęp do zasobów przechowywanych po stronie serwera W przedstawionym tutaj przykładzie wstawiliśmy na stronę WWW aktualną datę według serwera WWW. Gdybyśmy wstawiali datę, korzystając z języka JavaScript, moglibyśmy tylko podawać datę według komputera, na którym działa przeglądarka WWW. Bez
Rozdział 3. ♦ Wprowadzenie do języka PHP
79
wątpienia nie jest to szczególnie ambitny przykład wykorzystania zasobów dostępnych po stronie serwera; o wiele większe wrażenie zrobi na przykład osadzanie na stronie danych pochodzących z bazy danych MySQL (to taka drobna wskazówka…).
Zmniejszenie obciążenia po stronie klienta Język JavaScript może znacznie opóźnić wyświetlanie stron WWW na wolniejszych komputerach, ponieważ przeglądarka przed wyświetleniem strony WWW musi najpierw wykonać skrypt. Natomiast w przypadku kodu skryptów interpretowanych po stronie serwera ciężar całej pracy spada na komputer serwera WWW, z którego można korzystać w takim zakresie, jakiego wymaga aplikacja.
Podstawowe polecenia i składnia Składnia języka PHP nie powinna być niczym nowym dla każdego, kto rozumie język C, C++, C#, Java, JavaScript, Perl lub jakikolwiek inny język wywodzący się z języka C. Jeżeli nie miałeś do czynienia z żadnym z tych języków albo w ogóle dopiero zaczynasz swoją przygodę z programowaniem, nie masz żadnych powodów do zmartwień! Skrypty PHP składają się z serii poleceń lub inaczej instrukcji (ang. statements). Serwer WWW musi najpierw wykonać jedną instrukcję, nim przejdzie do następnej. Instrukcje języka PHP, podobnie jak w każdym innym z wymienionych powyżej języków, zawsze należy zamknąć średnikiem (;). Oto przykład typowej instrukcji PHP: echo 'To jest
test!';
Jest to instrukcja echo, która służy do generowania treści (zwykle jest nią kod HTML) w celu przesłania jej do przeglądarki internetowej. Instrukcja echo po prostu pobiera przesłany tekst i umieszcza go w kodzie strony HTML, w miejscu, w którym znajduje się kod PHP. W tym przypadku przesłaliśmy jej łańcuch tekstu: 'To jest
test!'. Jak widać, zawiera on znaczniki HTML (
i ), co jest jak najbardziej dopuszczalne. Jeśli wstawimy tę instrukcję do pełnoprawnej strony WWW, otrzymamy następujący kod. Listing 3.2. echo.php
Prosty przykład PHP
80
PHP i MySQL. Witryna WWW oparta na bazie danych
Jeśli umieścimy ten plik na naszym serwerze WWW, przeglądarka oglądająca tę stronę otrzyma następujący kod:
Prosty przykład PHP
To jest test!
Nasz pierwszy skrypt today.php, którym zajmowaliśmy się już wcześniej, zawierał trochę bardziej złożoną instrukcję echo. Listing 3.3. today.php (fragment) echo date('l, F dS Y.');
Zamiast instrukcji echo przesyłać do wyświetlenia prosty łańcuch tekstu, w tej instrukcji przywołujemy wbudowaną funkcję o nazwie date i właśnie tej funkcji przekazujemy łańcuch tekstu 'l, F dS Y.'. Wbudowane funkcje możemy traktować jak polecenia, niewymagające przesyłania językowi PHP żadnych dodatkowych szczegółów. Język PHP posiada bowiem liczne wbudowane funkcje umożliwiające wykonywanie wielu działań, począwszy od wysyłania e-maili, a skończywszy na pracy z informacjami przechowywanymi w różnego typu bazach danych. Gdy wywołuje się funkcję języka PHP, zwyczajowo mówi się, że funkcja jest wołana (ang. calling). Większość wywołanych funkcji zwraca wartość. W takim przypadku PHP zastąpi wywołanie funkcji wartością, którą zwróci funkcja w wyniku jej wywołania. W naszym przykładzie instrukcja echo zawiera wywołanie funkcji date, która zwraca aktualną datę w postaci tekstowego ciągu znaków (zgodnie z formatem wskazanym przez tekstowy ciąg znaków zawarty w wywołaniu funkcji). Następnie instrukcja echo zwraca wartość zwróconą przez wywołaną funkcję. Dociekliwego czytelnika zainteresuje zapewne, dlaczego ująłem tekst najpierw w nawiasy (()), a potem w pojedynczy cudzysłów (''). Podobnie jak w języku SQL, w języku PHP cudzysłowy są używane do oznaczania początku i końca łańcucha tekstu, więc ich zastosowanie jest jak najbardziej usprawiedliwione. Nawiasy z kolei służą dwóm celom. Po pierwsze, wskazują, że chcemy wywołać właśnie funkcję date. Po drugie, oznaczają początek i koniec listy parametrów (albo argumentów), które chcielibyśmy
Rozdział 3. ♦ Wprowadzenie do języka PHP
81
przesłać funkcji, aby poinformować ją, jakie działanie ma wykonać. W przypadku funkcji date musimy jej przesłać łańcuch tekstu opisujący, w jakim formacie powinna wyświetlić datę1. W dalszej części książki przyjrzymy się również funkcjom, którym należy przesłać więcej niż jeden parametr. W tym przypadku poszczególne parametry będziemy oddzielać przecinkami. Natkniemy się również na funkcje, które wcale nie wymagają przesyłania im żadnych parametrów. Funkcje te jednak nadal wymagać będą podawania zaraz po nazwie nawiasów, tyle że między nimi nie trzeba niczego wpisywać.
Zmienne, operatory i komentarze Zmiennych w języku PHP używa się w prawie taki sam sposób jak w większości języków programowania. Osobom, które nie przeszły jeszcze programistycznej inicjacji, wyjaśniam: zmienną można traktować jak nazwę nadawaną pewnemu wymyślonemu pudełku, w którym można będzie umieścić dowolną literalną wartość. Przykładowo ta instrukcja tworzy zmienną o nazwie $testvariable (wszystkie nazwy zmiennych w języku PHP muszą się zaczynać od znaku dolara) i przypisuje jej literalną wartość 3: $testvariable = 3;
PHP jest językiem stosującym luźne typowanie (ang. loosely typed). Oznacza to, że pojedyncza zmienna może zawierać dane dowolnego typu: liczbę, łańcuch tekstu lub jakąś inną wartość, co więcej: typ przechowywanych może się zmieniać w czasie życia zmiennej. Dlatego przedstawiona tutaj instrukcja, jeśli zostanie wpisana po pierwszej, może swobodnie przypisać zmiennej $testvariable nową wartość. Wówczas zmienna zmodyfikuje typ przechowywanych danych: wcześniej przechowywała liczbę, a teraz będzie zawierać tekst: $testvariable = 'Trzy';
Znak równości, którego używaliśmy w dwóch ostatnich instrukcjach, nazywany jest operatorem przypisania (ang. assignment operator), ponieważ służy do przypisywania wartości zmiennym. Możemy korzystać również z innych operatorów umożliwiających wykonywanie operacji matematycznych na wartościach. Oto przykład: $testvariable $testvariable $testvariable $testvariable
= = = =
1 1 2 2
+ * /
1; 1; 2; 2;
// Przypisze zmiennej wartość 2 // Przypisze zmiennej wartość 0 // Przypisze zmiennej wartość 4 // Przypisze zmiennej wartość 1
Na podstawie powyższych przykładów można stwierdzić, że + jest operatorem dodawania, - jest operatorem odejmowania, * to operator mnożenia, zaś / to operator dzielenia. Wszystkie one są tak zwanymi operatorami arytmetycznymi, ponieważ wykonują operacje arytmetyczne na liczbach.
1
Pełny opis funkcji date można znaleźć w dokumentacji online dostępnej pod adresem http://www.php. net/date
82
PHP i MySQL. Witryna WWW oparta na bazie danych
Każdy z przedstawionych tu wierszy instrukcji zakończony jest komentarzem (ang. comment). Komentarze służą do opisywania, jakie działania nasz kod właściwie wykonuje — pozwalają wstawić do kodu objaśniający tekst, który interpreter PHP zignoruje podczas interpretowania skryptu. Komentarze zaczynają się od znaków // i muszą skończyć się w tym samym wierszu. Jeżeli komentarz ma znajdować się w więcej niż jednym wierszu, można go rozpocząć sekwencją znaków /* i zakończyć znakami */. W takim przypadku interpreter PHP zignoruje wszystko, co znajdzie się między tymi dwiema sekwencjami. W dalszej części książki komentarze nieraz posłużą do objaśniania fragmentów prezentowanego kodu. Wróćmy jednak do operatorów. Istnieje jeszcze jeden bardzo użyteczny operator sklejania (ang. concatenation operator), umożliwiający łączenie ze sobą łańcuchów tekstu: $testvariable = 'Hej ' . 'tam!';
// Przypisuje zmiennej tekst "Hej tam!"
Zmienne można stosować praktycznie wszędzie tam, gdzie moglibyśmy użyć zwykłej literalnej wartości. Przeanalizujmy następujące instrukcje: $var1 = 'PHP'; $var2 = 5; $var3 = $var2 + 1; $var2 = $var1; echo $var1; echo $var2; echo $var3; echo $var1 . ' rządzi!'; echo "$var1 rządzi!"; echo '$var1 rządzi!';
// Przypisuje wartość 'PHP' zmiennej $var1 // Przypisuje wartość 5 zmiennej $var2 // Przypisuje wartość 6 zmiennej $var3 // Przypisuje wartość 'PHP' zmiennej $var2 // Zwraca 'PHP' // Zwraca 'PHP' // Zwraca '6' // Zwraca 'PHP rządzi!' // Zwraca 'PHP rządzi!' // Zwraca '$var1 rządzi!'
Szczególną uwagę warto zwrócić na dwa ostatnie wiersze. Możemy zatem wstawić nazwę zmiennej wprost do łańcucha tekstu i jeśli ujmiemy ten łańcuch w podwójne cudzysłowy, zamiast w pojedyncze, PHP wyświetli wartość zmiennej, a nie tylko jej nazwę. Proces konwertowania nazwy zmiennej na przechowywaną w tej zmiennej wartość nazywany jest interpolacją zmiennej (ang. variable interpolation). Ostatni wiersz pokazuje jednak, że jeśli łańcuch tekstu będzie ujęty w pojedynczy cudzysłów, PHP nie będzie interpolował zawartych w łańcuchu nazw zmiennych na skrywane pod nimi wartości.
Tablice Tablica (ang. array) to specjalny rodzaj zmiennej, która może zawierać wiele wartości. Jeśli wyobrazimy sobie zmienną jako pudełko przechowujące pewną wartość, to tablica będzie pudełkiem z wieloma przegródkami, w którym każda z przegródek może zawierać osobną wartość. Najprostszym sposobem na utworzenie tablicy w języku PHP jest skorzystanie z wbudowanej w niego funkcji array: $myarray = array('jeden', 2, '3');
Rozdział 3. ♦ Wprowadzenie do języka PHP
83
Kod ten tworzy tablicę $myarray, która zawiera trzy wartości 'jeden', 2 i '3'. Podobnie jak zwykła zmienna każda z przegródek tablicy może przechowywać zmienne dowolnego typu. W tym przypadku pierwsze pole tablicy zawiera łańcuch tekstu, podczas gdy drugie i trzecie — liczbę. Aby pobrać wartość przechowywaną w tablicy, trzeba znać jej indeks (ang. index). Zazwyczaj jako indeksów tablice używają kolejnych liczb począwszy od zera, wskazujących pozycję w tablicy, pod którą można znaleźć daną wartość. Oznacza to, że pierwsza wartość (lub inaczej element) tablicy będzie miała indeks 0, druga — indeks 1, trzecia — indeks 2 i tak dalej. Innymi słowy, indeksem n-tego elementu tablicy będzie liczba n–1. Jeśli znamy indeks wartości, która nas interesuje, możemy pobrać tę wartość, umieszczając odpowiedni numer indeksu w nawiasie kwadratowym po nazwie zmiennej tablicy: echo $myarray[0]; echo $myarray[1]; echo $myarray[2];
// Zwraca 'jeden' // Zwraca '2' // Zwraca '3'
Każda wartość przechowywana w tablicy to tak zwany element tablicy. Indeks ujęty w nawiasy kwadratowe można również wykorzystać, by utworzyć nowy element tablicy lub przypisać nową wartość już istniejącemu elementowi: $myarray[1] = 'dwa'; $myarray[3] = 'cztery';
// Przypisz nową wartość // Utwórz nowy element
Jeśli chcemy dodać wartość na końcu tabeli, używamy jak zwykle operatora przypisania, ale po nazwie zmiennej tablicy wpisujemy tylko puste nawiasy kwadratowe: $myarray[] = 'piąty element'; echo $myarray[4]; // Zwraca 'piąty element'
Jako indeksy tablic najczęściej wykorzystuje się właśnie liczby, choć jest to tylko konwencja i istnieje również alternatywa. W charakterze indeksów można również używać łańcuchów tekstu, tworząc w ten sposób tablicę asocjacyjną (ang. associative array). Tablica taka nazwana została asocjacyjną, ponieważ wiąże (czyli inaczej — asocjuje) wartości z odpowiednimi opisowymi indeksami. W tym przypadku powiążemy daty urodzenia (mające postać ciągu znaków) z odpowiednimi imionami (które są naszymi indeksami): $birthdays['Kevin'] = '1978-04-12'; $birthdays['Stefania'] = '1980-05-16'; $birthdays['Dawid'] = '1983-09-09';
Funkcja array również pozwala na tworzenie tabel asocjacyjnych, jeśli wolimy tę metodę. Oto przykład tworzenia tabeli dat urodzenia $birthdays: $birthdays = array('Kevin' => '1978-04-12', 'Stefania' => '1980-05-16', 'Dawid' => '1983-09-09');
Jeśli zechcemy poznać datę urodzenia Kevina, będziemy mogli obejrzeć ją, używając imienia jako indeksu: echo 'Moja data urodzenia to: ' . $birthdays['Kevin'];
84
PHP i MySQL. Witryna WWW oparta na bazie danych
Jak się przekonamy dalej, ten typ tabeli jest szczególnie przydatny, gdy w języku PHP zajmujemy się interakcją i komunikacją z użytkownikiem. W dalszej części książki przedstawię również inne zastosowania tablic.
Interakcja z użytkownikiem i formularze Większość współczesnych internetowych aplikacji bazodanowych nie może się ograniczać tylko do dynamicznego generowania stron zawierających dane pobierane z bazy, lecz musi również zapewnić odpowiedni stopień interakcji nawet wtedy, jeśli są to zwykłe, najprostsze wyszukiwarki. Weterani programowania w JavaScripcie przyzwyczajeni są zapewne do myślenia o interaktywności w kategoriach funkcji obsługi poleceń, które pozwalają na bezpośrednie reagowanie na to, co zrobi użytkownik — na przykład skierowanie kursora nad umieszczone na stronie łącze. Języki skryptowe działające po stronie serwera mają jednak znacznie mniejszą swobodę, jeśli chodzi o możliwości bezpośredniej interakcji z użytkownikiem. Kod PHP wykonywany jest bowiem wówczas, gdy do serwera dociera żądanie; interakcja z użytkownikiem jest więc możliwa tylko poprzez przesyłanie go między stronami: użytkownik wysyła do serwera żądania, a serwer odpowiada mu kolejnymi, generowanymi dynamicznie stronami2. Kluczem do tworzenia interaktywnej komunikacji za pomocą PHP jest zrozumienie technik, którymi możemy się posłużyć, by przesyłać informacje wykorzystywane w interakcji z użytkownikiem wraz z wysłanym przez niego (lub nią) żądaniem nowej strony WWW. Jak się okaże, w języku PHP nie jest to szczególnie trudne. Najprostsza metoda przesyłania informacji wraz z żądaniem strony wykorzystuje łańcuch zapytania URL (ang. URL query string). Zapewne czytelnicy zetknęli się już nieraz z adresem URL, w którym po nazwie pliku pojawiał się znak zapytania. To właśnie przykład zastosowania tej techniki. Jeśli na przykład w wyszukiwarce Google poszuka się stron pod kątem hasła „SitePoint”, wyniki wyszukiwania zostaną wyświetlone na stronie o następującym adresie URL: http://www.google.com/search?hl=pl&q=SitePoint&btnG=Google+Search&meta=
2
Do pewnego stopnia uległo to zmianie dzięki obserwowanemu w ostatnich latach rozwojowi technik Ajax w świecie JavaScriptu. Obecnie w odpowiedzi na czynność wykonaną przez użytkownika, na przykład poruszenie myszą, kod JavaScript potrafi wysłać żądanie do serwera i w ten sposób wywołać skrypt PHP. Jednak dla celów naszej książki skupimy się tylko na aplikacjach, w których nie będziemy stosować technologii Ajax. Aby zobaczyć, w jaki sposób można łączyć PHP i Ajax, warto sięgnąć po książkę AJAX i PHP. Tworzenie interaktywnych aplikacji internetowych (http://helion.pl/ksiazki/ajaphp.htm), której autorami są Cristian Darie, Bogdan Brinzarea, Filip Cherecheş-Toşa i Mihai Bucica (Wydawnictwo Helion, 2006).
Rozdział 3. ♦ Wprowadzenie do języka PHP
85
Czy zauważyłeś znak zapytania w adresie URL? Widzisz, w jaki sposób w tekście znajdującym się po znaku zapytania osadzone zostały wyszukiwane hasło (SitePoint) i nazwa klikniętego przycisku (Google+Search)? Informacje te są przesyłane wraz z żądaniem do strony http://www.google.com/search. Wykonajmy samodzielnie prosty przykład. Utworzymy zwykły powitalny plik HTML o nazwie welcome1.html (nie jest tutaj potrzebne rozszerzenie .php, ponieważ plik nie będzie zawierał kodu PHP) i dodamy do niego poniższe łącze. Listing 3.4. welcome1.html (fragment) Hej, Jestem Kevin!
Jest to łącze do pliku welcome1.php, jednak wraz z odwoływaniem się do pliku przesyłamy również w żądaniu zmienną. Zmienna przesyłana jest jako część łańcucha zapytania, a właściwie ta część adresu URL, która następuje po znaku zapytania (?). Zmienna nazywa się name (imię), a jej wartość to Kevin. Podsumowując: utworzyliśmy łącze, które ładuje plik welcome1.php i informuje kod PHP osadzony w tym pliku, że wartość zmiennej name to Kevin. Aby dobrze zrozumieć, jaki będzie efekt działania tego łącza, przyjrzyjmy się plikowi welcome1.php. Zapiszmy go w tym celu jako nowy plik HTML, ale tym razem z rozszerzeniem .php — informując w ten sposób serwer WWW, że w tym pliku ma szukać kodu PHP, który powinien zinterpretować. W samym pliku natomiast musimy umieścić poniższy kod. Listing 3.5. welcome1.php (fragment)
Umieść obydwa pliki (welcome1.html i welcome1.php) na serwerze WWW i wywołaj pierwszy z nich w przeglądarce internetowej (adres URL powinien mieć postać http://localhost/welcome1.html albo http://localhost:8080/welcome1.html, jeżeli serwer WWW działa na porcie innym niż 80). Następnie kliknij łącze widoczne na pierwszej stronie, by załadować skrypt PHP. Na ekranie przeglądarki powinna pojawić się strona WWW z komunikatem: „Witamy na naszej witrynie, Kevin!”, tak jak to zostało przedstawione na rysunku 3.1. PHP automatycznie utworzy zmienną tablicową o nazwie $_GET, która zawierać będzie wartości przesyłane w łańcuchu zapytania. Tablica $_GET jest tablicą asocjacyjną, więc wartość zmiennej name przesłanej w łańcuchu zapytania można odczytać, wpisując $_GET['name']. Nasz skrypt przypisuje tę wartość zwykłej zmiennej PHP ($name), której wartość wyświetli następnie w ramach łańcucha zwracanego przez instrukcję echo. Przyjrzyjmy się bliżej kodowi, który jest wykonywany. Najważniejszy jest jego następujący wiersz.
86
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 3.1. Witanie użytkowników po imieniu
Listing 3.6. welcome1.php (fragment) $name = $_GET['name'];
Jeżeli uważnie przeczytałeś podrozdział pod tytułem „Tablice”, bez trudu zrozumiesz, co robi powyższy wiersz. Otóż przypisuje on zmiennej o nazwie $name wartość przechowywaną w elemencie 'name' tablicy o nazwie $_GET. Ale skąd bierze się tablica $_GET? Okazuje się, że $_GET jest jedną z wielu zmiennych, które PHP tworzy automatycznie w momencie otrzymania żądania od przeglądarki. PHP tworzy zmienną $_GET jako tablicę zmiennych, która zawiera wszelkie wartości przekazane w ciągu zapytania. $_GET jest tablicą asocjacyjną, dzięki czemu wartość zmiennej name przekazanej w ciągu zapytania może zostać odczytana za pomocą instrukcji $_GET['name']. Skrypt welcome1.php przypisuje tę wartość zwykłej zmiennej PHP o nazwie $name, po czym wyświetla ją jako element tekstowego ciągu znaków przy użyciu instrukcji echo. Listing 3.7. welcome1.php (fragment) echo 'Witamy na naszej witrynie, ' . $name . '!';
Wartość zmiennej $name jest wstawiana do wynikowego ciągu znaków przez operator sklejania (.), o którym wspomniałem w podrozdziale „Zmienne, operatory i komentarze”. Ale uwaga! W przedstawionym kodzie znajduje się poważna dziura bezpieczeństwa! Wprawdzie bardzo łatwo nauczyć się programować w PHP, lecz jednocześnie bardzo łatwo narazić witrynę napisaną w PHP na niebezpieczeństwo, jeżeli jej twórca nie zna zagrożeń, z jakimi można się spotkać. Zanim bardziej skupimy się na poznaniu języka, chcę najpierw zwrócić szczególną uwagę właśnie na to zagrożenie, ponieważ wynika ono z chyba obecnie najczęściej spotykanych niebezpieczeństw czyhających w sieci WWW. Oto przyczyna zagrożenia: skrypt welcome1.php generuje stronę z treścią, nad którą kontrolę sprawuje użytkownik. W tym przypadku chodzi o zmienną $name. Chociaż wartość zmiennej $name będzie w normalnych okolicznościach pochodzić z ciągu zapy-
Rozdział 3. ♦ Wprowadzenie do języka PHP
87
tania URL przekazywanego w łączu znajdującym się na stronie welcome1.html, złośliwy użytkownik może zmienić ten URL w taki sposób, aby przesłać do zmiennej $name inną wartość. Aby zobaczyć, w czym rzecz, ponownie kliknij łącze na stronie welcome1.html. Gdy wyświetli się strona wynikowa (z powitaniem zawierającym imię „Kevin”), spójrz na adres URL znajdujący się w pasku adresów przeglądarki. Powinien on wyglądać mniej więcej tak: http://localhost/welcome1.php?name=Kevin
A teraz zmień adres URL: przed imieniem dodaj znacznik , a po nim znacznik w następujący sposób: http://localhost/welcome1.php?name=Kevin
Naciśnij Enter, aby otworzyć zmieniony adres URL i zwróć uwagę, że teraz imię wyświetlane na stronie jest zapisane pogrubioną czcionką, co widać na rysunku 3.2. Rysunek 3.2. Brak zabezpieczeń tylko rozzuchwali złośliwych użytkowników!
Widzisz, co się stało? Użytkownik może wpisać w adresie URL dowolny kod HTML, a skrypt PHP dołączy go do kodu wygenerowanej strony. Jeżeli zmieniony kod zawiera tylko niewinne znaczniki , to jeszcze nie ma wielkiego problemu, lecz szczególnie złośliwy użytkownik może wpisać kod JavaScript, który wykona niepożądane operacje — na przykład wykradnie hasła użytkownika. W takim przypadku napastnikowi wystarczy tylko opublikować zmodyfikowane łącze na jakiejś innej witrynie, którą sam kontroluje, a następnie zachęcić użytkowników do jego kliknięcia. Napastnik może nawet umieścić łącze w wiadomości poczty elektronicznej i wysłać ją do użytkowników. Jeżeli któryś z użytkowników kliknie łącze, kod spreparowany przez napastnika zostanie osadzony na stronie i pułapka będzie gotowa! Bardzo nie lubię straszyć złośliwymi użytkownikami, którzy narażą odbiorców na niebezpieczeństwo przez odpowiednią zmianę w kodzie PHP zwłaszcza wtedy, gdy dopiero uczysz się programować w tym języku. Jednak faktem jest, że największą słabością
88
PHP i MySQL. Witryna WWW oparta na bazie danych
PHP jako języka programowania jest łatwość, z jaką można narazić się na tego typu niebezpieczeństwa. Ktoś może powiedzieć, że w trakcie poważnej nauki programowania w PHP najwięcej czasu powinno się poświęcić na unikanie niebezpieczeństw. Jednak im wcześniej się z nimi spotkasz, tym szybciej się przyzwyczaisz do technik ich unikania i tym mniejszą trudność techniki te będą sprawiać w trakcie dalszej nauki. Zatem w jaki sposób można wygenerować stronę, która będzie zawierać imię użytkownika, a jednocześnie nie stanie się przedmiotem ataku złośliwych użytkowników? Rozwiązanie polega na potraktowaniu wartości przypisywanej zmiennej $name jak zwykły tekst wyświetlany w treści strony, a nie jako kod HTML przeznaczonego do wstawienia w kodzie strony. Różnica jest subtelna, dlatego zatrzymajmy się jeszcze przez chwilę nad tym zagadnieniem. Skopiuj plik welcome1.html i zmień jego nazwę na welcome2.html. Następnie zmień łącze znajdujące się na stronie tak, by wskazywało ono plik welcome2.php zamiast welcome1.php. Listing 3.8. welcome2.html (fragment) Hej, Jestem Kevin!
Skopiuj również plik welcome1.php i zmień jego nazwę na welcome2.php, a następnie zmień zawarty w nim kod PHP tak, aby wyglądał następująco. Listing 3.9. welcome2.php (fragment)
W kodzie wykonywanych jest sporo nowych operacji, dlatego rozbierzmy go na czynniki pierwsze. Pierwszy wiersz jest taki sam jak poprzednio, to znaczy przypisuje zmiennej $name wartość elementu 'name' tablicy $_GET. Instrukcja echo, która znajduje się w następnym wierszu, wygląda już jednak zupełnie inaczej. W poprzedniej wersji wartość zmiennej $name była po prostu zwracana przez instrukcję echo w niezmienionej postaci, natomiast w tej wersji kodu użyto wbudowanej funkcji języka PHP o nazwie htmlspecialchars, aby wykonać bardzo ważne przekształcenie. Jak pamiętamy, niebezpieczeństwo wiązało się z faktem, że w skrypcie welcome1.php kod HTML w zmiennej $name jest umieszczany bezpośrednio w kodzie generowanej strony i dlatego może on wykonywać wszelkie operacje, które wykonywać może zwykły kod HTML. Z kolei funkcja htmlspecialchars przekształca „specjalne znaki HTML”, takie jak „” na znakowe elementy języka HTML, takie jak < i >. Dzięki temu przeglądarka nie zinterpretuje ich jako elementów kodu HTML. Za chwilę objaśnię bliżej, na czym to rozwiązanie polega.
Rozdział 3. ♦ Wprowadzenie do języka PHP
89
Najpierw przyjrzyjmy się bliżej nowemu kodowi. Wywołanie funkcji htmlspecialchars jest pierwszym w tej książce przykładem funkcji PHP, która przyjmuje więcej niż jeden parametr. Oto wywołanie funkcji: htmlspecialchars($name, ENT_QUOTES, 'UTF-8')
Pierwszym parametrem jest zmienna $name (czyli tekst, który ma podlegać przekształceniu). Drugi parametr to stała języka PHP3 ENT_QUOTES, która nakazuje funkcji htmlspecialchars, aby oprócz innych specjalnych znaków przekształcane były również znaki apostrofów i cudzysłowów. Trzeci parametr to ciąg znaków 'UTF-8'; wskazuje on językowi PHP system kodowania znaków, którego należy użyć do zinterpretowania przekazanego tekstu. Wady i zalety kodowania UTF-8 w języku PHP Być może już zwróciłeś uwagę, że wszystkie przykładowe strony HTML prezentowane dotąd w książce zawierają na początku znacznik :
Znacznik ten informuje przeglądarkę, do której trafia strona, że kod HTML strony 4 jest zakodowany jako tekst UTF-8 . Na jednej z następnych stron znajduje się punkt o tworzeniu formularzy HTML. Dzięki kodowaniu stron w UTF-8 użytkownicy będą mogli wpisywać tekst zawierający tysiące zagranicznych znaków, których w innym przypadku witryna nie potrafiłaby obsługiwać. Niestety, wiele wbudowanych funkcji PHP, takich jak htmlspecialchars, domyślnie przyjmuje, że używany jest znacznie prostszy system kodowania znaków, czyli ISO-8859-1. Dlatego tym funkcjom trzeba jawnie wskazać, że używane jest kodowanie UTF-8. Jeżeli masz taką możliwość, w używanym przez siebie edytorze tekstu również powinieneś wskazać, by pliki HTML i PHP zapisywał z kodowaniem UTF-8. Jest to jednak wymagane tylko wówczas, gdy w kodzie HTML lub PHP trzeba wpisywać bardziej zaawansowane znaki (na przykład dywizy) albo znaki diaktrytyczne (na przykład „ę”). Kod, który piszemy w tej książce, jest bezpieczny, ponieważ używamy w nim elementów języka HTML (na przykład ’ w miejsce prawego nawiasu klamrowego), które zawsze będą prawidłowo interpretowane.
W przeglądarce otwórz stronę welcome2.html i kliknij łącze, które teraz wskazuje na plik welcome2.php. Ponownie wyświetlony zostanie komunikat powitalny „Witaj na naszej witrynie, Kevin!”. Tak jak poprzednio, zmień adres URL tak, aby otoczyć imię znacznikami i : http://localhost/welcome2.php?name=Kevin 3
Stała PHP to w pewnym sensie zmienna, której wartości nie można zmienić. W odróżnieniu od zmiennych, stałe nie zaczynają się znakiem dolara. PHP posiada szereg wbudowanych stałych, takich jak ENT_QUOTES, za pomocą których kontroluje się zachowanie wbudowanych funkcji, takich jak htmlspecialchars.
4
UTF-8 to jeden z wielu standardów reprezentacji tekstu jako serii zer i jedynek w pamięci komputera — tak zwanych standardów kodowania znaków. Jeśli chcesz dowiedzieć się więcej na temat kodowania znaków, przeczytaj artykuł pod tytułem „The Definitive Guide to Web Character Encoding” (http://www.sitepoint.com/article/guide-web-character-encoding/).
90
PHP i MySQL. Witryna WWW oparta na bazie danych
Tym razem po kliknięciu klawisza Enter imię nie będzie już wyświetlane pogrubioną czcionką, lecz na stronie pojawi się dokładnie taki tekst, jaki został wpisany, co widać na rysunku 3.3. Rysunek 3.3. Nie wygląda to zbyt ciekawie, ale przynajmniej jest bezpieczne!
Gdy spojrzysz na źródło strony, zobaczysz, że funkcja htmlspecialchars prawidłowo wykonała swoje zadanie i przekształciła znaki „” znajdujące się w imieniu przekazanym w adresie URL na odpowiadające im znakowe elementy języka HTML, czyli < i >. To sprawi, że złośliwi użytkownicy nie będą mogli wstrzyknąć na witrynę niebezpiecznego kodu. Każda próba takiego działania zakończy się po prostu wyświetleniem kodu na stronie w postaci zwykłego tekstu, bez żadnych negatywnych konsekwencji. Funkcji htmlspecialchars będziemy używać w tej książce bardzo często, aby zabezpieczyć się przed opisanym niebezpieczeństwem. Jeżeli wciąż masz problem z pełnym zrozumieniem sposobu zastosowania tej funkcji, nie martw się. Niedługo korzystanie z niej stanie się Twoją drugą naturą. Na razie skupmy się na bardziej zaawansowanych sposobach przekazywania wartości do skryptów PHP w momencie ich wywołania. Przekazywanie pojedynczej zmiennej w ciągu zapytania jest bardzo proste, jednak okazuje się, że w razie potrzeby można przekazać więcej niż jedną wartość! Spójrzmy na nieco bardziej skomplikowaną wersję poprzedniego przykładu. Plik welcome2.html należy zapisać jako welcome3.html i zmienić łącze tak, by wskazywało na plik welcome3.php oraz zawierało poniższy ciąg zapytania. Listing 3.10. welcome3.html (fragment) Hej, Jestem Kevin Yank!
Tym razem w łączu przesyłamy dwie zmienne: firstname (imię) i lastname (nazwisko). Zmienne te oddzielane są w łańcuchu zapytania znakiem ampersandu (czyli znakiem &, który w kodzie HTML musi być zapisywany jako &). Oczywiście, można przesyłać więcej wartości, pod warunkiem że każdą parę nazwa=wartość będziemy oddzielać znakiem &.
Rozdział 3. ♦ Wprowadzenie do języka PHP
91
Tak jak poprzednio, obu tych wartości użyjemy w naszym pliku welcome3.php. Listing 3.11. welcome3.php (fragment)
Rezultat został przedstawiony na rysunku 3.4. Rysunek 3.4. Tworzenie jeszcze bardziej spersonalizowanego komunikatu powitalnego
Mimo pewnych sukcesów nie osiągnęliśmy jeszcze pełnej interakcji z użytkownikiem, tak by mógł wpisać dowolne informacje i obejrzeć je przetworzone przez kod PHP. Kontynuujmy nasz przykład spersonalizowanej wiadomości powitalnej; moglibyśmy umożliwić użytkownikowi wpisanie swojego imienia, które następnie powinno pojawić się na stronie wynikowej. Aby użytkownik mógł wpisywać wartości, potrzebny będzie formularz HTML. Należy utworzyć nowy plik HTML o nazwie welcome4.html i wpisać w nim kod HTML, który będzie stanowił definicję formularza. Listing 3.12. welcome4.html (fragment)
Imię:
Nazwisko:
92
PHP i MySQL. Witryna WWW oparta na bazie danych
Samozamykające się znaczniki Niech nie przestraszą was ukośniki pojawiające się na końcu w niektórych znacznikach (na przykład ). Standard kodowania stron WWW, czyli XHTML, postuluje korzystanie z ukośników w każdym znaczniku, który nie posiada znacznika zamykającego, czyli między innymi w znacznikach czy . Wielu programistów woli trzymać się standardu HTML zamiast XHTML. I rzeczywiście, jest to tematem pewnego sporu między różnymi grupami programistów WWW. Opracowywany właśnie standard HTML 5 pozostawia w tej kwestii wybór programistom, dlatego trudno powiedzieć, by jedno z tych rozwiązań było „bardziej poprawne” od drugiego. Jeżeli chcesz poznać przesłanki, które należy wziąć pod uwagę przed samodzielnym podjęciem decyzji, zajrzyj na odpowiednią stronę witryny SitePoint HTML Reference5.
Strona z formularzem przygotowanym przez ten kod została przedstawiona na rysunku 3.56. Rysunek 3.5. Przygotowywanie własnego komunikatu powitalnego
Utwórz również kopię pliku welcome3.php i nadaj jej nazwę welcome4.php. W tym pliku nie trzeba nic zmieniać. Formularz ten wywiera ten sam skutek, jak drugie łącze, które omawialiśmy (z first ´name=Kevin&lastname=Yank w łańcuchu zapytania), tyle że teraz możemy wprowadzić dowolnie wybrane imię i nazwisko. Kiedy klikniemy zatwierdzający formularz 5
http://reference.sitepoint.com/html/html-vs-xhtml
6
Formularz ma bardzo surową postać. Zastosowanie kaskadowego arkusza stylów CSS sprawiłoby, że formularz — a także inne strony prezentowane w książce — przybrałyby o wiele atrakcyjniejszą postać. Ponieważ jednak jest to książka o PHP i MySQL, nie będziemy się zajmować uatrakcyjnianiem wyglądu przykładowych stron. Więcej informacji na temat stosowania stylów CSS w formularzach można znaleźć na przykład w książce CSS. Projektowanie profesjonalnych stron WWW (http://helion.pl/ksiazki/cssppw.htm), Wydawnictwo Helion, 2009.
Rozdział 3. ♦ Wprowadzenie do języka PHP
93
przycisk Submit (opatrzony etykietą „Wyślij”), przeglądarka załaduje stronę welcome4.php, automatycznie dodając zmienne i ich wartości do łańcucha zapytania. Nazwy zmiennych pobierze z atrybutów name znaczników , a wartości z informacji, które użytkownik wpisał w polach tekstowych formularza. Apostrofy w polach formularza Jeżeli ego masz tak przerośnięte, jak większość programistów (nie wyłączając mnie), na pewno od razu skorzystałeś z okazji i wpisałeś w formularzu swoje imię i nazwisko. Cóż w tym złego? Jeżeli w nazwisku znajduje się apostrof (na przykład Molly O’Reilly), wówczas komunikat powitalny widoczny na stronie może zawierać przed apostrofem mało estetyczny znak lewego ukośnika (czyli będzie miał treść „Witaj na naszej witrynie, Molly O\’Reilly!”). Obecność irytującego lewego ukośnika jest wynikiem działania zabezpieczenia języka PHP o nazwie magiczne apostrofy (ang. magic quotes), które poznamy w rozdziale 4. Na razie nie będziemy się nim zajmować.
Atrybut method znacznika form służy do informowania przeglądarki, w jaki sposób ma wysyłać zmienne i ich wartości razem z żądaniem. Wartość get tego atrybutu (zastosowana w pliku welcome4.html powyżej) powoduje, że zmienne i ich wartości zostaną wysłane w łańcuchu zapytania (i trafią do tablicy $_GET języka PHP), ale istnieje też drugi sposób. Nie zawsze wysyłanie wartości w łańcuchu zapytania jest pożądane — a czasami może być niemożliwe z przyczyn technicznych. Zastanówmy się na przykład, co by się stało, gdybyśmy w formularzu umieścili znacznik tworzący pole tekstowe, w którym można wpisać nawet dość długi tekst? Adres URL, którego łańcuch zawierałby kilka akapitów tekstu, byłby idiotycznie długi i prawdopodobnie przekroczyłby maksymalną długość adresu URL dopuszczaną przez dzisiejsze przeglądarki. Alternatywnym rozwiązaniem jest wysłanie przez przeglądarkę informacji w sposób niewidoczny, za kulisami. Utwórz kopię pliku welcome4.html i nadaj jej nazwę welcome5.html. Kod formularza na nowej stronie nie ulegnie zmianie — tyle tylko, że tam, gdzie atrybut method formularza miał wartość get, tym razem powinien przybrać wartość post. Oczywiście, zmienić trzeba również atrybut action tak, by wskazywał na plik welcome5.php. Listing 3.13. welcome5.html (fragment)
Imię:
Nazwisko:
94
PHP i MySQL. Witryna WWW oparta na bazie danych
Nowa wartość atrybutu method nakazuje przeglądarce, by zmienne formularza były przesyłane w sposób niewidoczny, jako część wywołania strony, a nie osadzane w ciągu zapytania URL. Należy znowu utworzyć kopię pliku welcome4.php i nadać jej nazwę welcome5.php. Nie wysyłamy już zatem zmiennych jako części łańcucha zapytania i w związku z tym nie trafią one do tablicy $_GET. Zamiast tego umieszczane są w innej tablicy zarezerwowanej specjalnie dla zmiennych wysyłanych metodą POST, a mianowicie $_POST. Dlatego też musimy zmodyfikować skrypt welcome5.php, by mógł pobierać wartości z tej nowej tablicy. Listing 3.14. welcome5.php (fragment)
Na rysunku 3.6 pokazano, jak wyglądać będzie strona powitalna po wysłaniu imienia i nazwiska nową metodą. Rysunek 3.6. Ta spersonalizowana strona powitalna została przygotowana bez wysyłania wartości w łańcuchu zapytania
Formularz ten jest od strony funkcjonalnej zupełnie taki sam jak poprzedni. Jedyna różnica polega na tym, że adres URL strony, która zostanie załadowana, gdy użytkownik kliknie Wyślij, nie będzie tym razem zawierać łańcucha zapytania. Z jednej strony, powyższe rozwiązanie ma tę zaletę, że pozwala na przesyłanie długich lub sekretnych wartości (takich jak hasła) wprowadzonych w formularzu, tak by nie pojawiały się w łańcuchu zapytania. Z drugiej jednak strony, posiada wadę: jeśli bowiem użytkownik spróbuje dodać otrzymaną w ten sposób stronę do zakładek w przeglądarce, zakładka taka okaże się bezużyteczna, ponieważ łańcuch adresu nie będzie zawierał wprowadzonych wartości. Jest to jeden z głównych powodów, dla których wyszuki-
Rozdział 3. ♦ Wprowadzenie do języka PHP
95
warki internetowe wykorzystują do przesyłania wartości łańcuchy zapytania. Jeśli zaznaczymy jako zakładkę stronę otrzymaną jako wynik wyszukiwania w wyszukiwarce, takiej jak Google, będziemy mogli później bez problemów powrócić do rezultatów wyszukiwania, ponieważ nasze terminy wyszukiwania zawarte będą w adresie URL zakładki. Czasami zależy nam na możliwości sięgnięcia do zmiennej, bez względu na to, czy została wysłana jako część łańcucha zapytania, czy też za pomocą metody post. W takim przypadku pomocna okazuje się tablica $_REQUEST. Zawiera ona wszystkie zmienne, które pojawiają się w obu tablicach $_GET i $_POST. Wiedząc o tej zmiennej, możemy zmodyfikować nasz skrypt przetwarzający dane z formularza jeszcze raz, tym razem tak aby był w stanie pobierać wartości imienia i nazwiska, niezależnie od tego, jaką metodą zostałyby przesłane do serwera. Listing 3.15. welcome6.php (fragment)
W ten sposób omówiliśmy podstawy wykorzystywania formularzy w przygotowywaniu najprostszej formy interakcji z użytkownikiem, korzystając z możliwości języka PHP. W następnych przykładach zaprezentuję bardziej zaawansowane techniki.
Struktury sterujące Wszystkie przykłady kodu PHP, z którymi zapoznaliśmy się do tej pory, były albo prostymi, składającymi się z jednej instrukcji skryptami, które wyświetlały na stronie WWW łańcuch tekstu, albo też skryptami zawierającymi serię instrukcji wykonywanych jedna po drugiej. Czytelnicy, którzy mieli okazję pisać programy w innych językach programowania (takich jak JavaScript, C lub BASIC), wiedzą jednak, że prawdziwe programy rzadko kiedy bywają aż tak proste. Język PHP, tak jak inne języki programowania, dostarcza narzędzi, które pozwalają zarządzać przepływem sterowania (ang. flow of control). Oznacza to po prostu, że język PHP udostępnia specjalne instrukcje pozwalające na odejście od standardowego porządku wykonywania instrukcji jedna po drugiej, który do tej pory dominował w naszych przykładach. Tego typu instrukcje nazywane są ogólnie strukturami sterującymi (ang. control structures). Trudno zrozumieć, o co chodzi? Bez obaw! Pokażę kilka przykładów, które, mam nadzieję, przybliżą to zagadnienie. Najbardziej podstawową i najczęściej wykorzystywaną strukturą sterującą jest instrukcja if. Przebieg programu, w którym zastosowano instrukcję if, zobrazowano na rysunku 3.7.
96
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 3.7. Logiczny przebieg wykonania instrukcji if7
Oto podstawowy schemat instrukcji if w kodzie PHP: if (warunek) { // Instrukcja (instrukcje) zostaną wykonane // jeśli warunek jest spełniony (prawdziwy). }
Ta struktura sterująca pozwala nakazać językowi PHP, by zbiór instrukcji został wykonany jedynie wówczas, gdy spełniony będzie określony warunek. Jeśli wybaczycie mi odrobinę próżności, oto wspaniały przykład modyfikacji spersonalizowanej strony powitalnej, którą oglądaliśmy powyżej. Najpierw utwórz kopię pliku welcome6.html i nadaj mu nazwę welcome7.html. Dla uproszczenia zmienimy formularz znajdujący się na stronie w taki sposób, by do skryptu welcome7.php przekazywał tylko jedną zmienną name. Listing 3.16. welcome7.html (fragment)
Imię:
Teraz stwórz kopię pliku welcome6.php i nazwij ją welcome7.php, po czym zastąp znajdujący się w niej kod PHP następującym skryptem. Gdy zmienna imienia name przesyłana stronie będzie miała wartość 'Kevin', wyświetlony zostanie specjalny wariant komunikatu powitalnego, co zostało pokazane na rysunku 3.8. 7
Oryginał tego diagramu oraz kilku kolejnych jemu podobnych, a prezentowanych w książce, został opracowany przez Camerona Adamsa na potrzeby książki Simply JavaScript (Melbourne, SitePoint, 2006), którą napisaliśmy wspólnie. Diagramy wykorzystałem również w tej książce za zgodą Camerona, za co mu w tym miejscu dziękuję.
Rozdział 3. ♦ Wprowadzenie do języka PHP
97
Listing 3.17. welcome7.php (fragment) $name = $_REQUEST['name']; if ($name == 'Kevin') { echo 'Witamy, o przewspaniały!'; }
Rysunek 3.8. Dobrze być królem
Jeśli w formularzu wpisane zostanie imię inne niż Kevin, strona okaże się mało przyjazna dla użytkownika — kod warunkowy zawarty w instrukcji if nie zostanie wykonany i w konsekwencji strona wynikowa będzie pusta! Aby udostępnić alternatywną wersję strony powitalnej przeznaczoną dla wszystkich maluczkich, którzy mają imię inne niż Kevin, można zamiennie użyć instrukcji if-else. Strukturę instrukcji if-else zobrazowano na rysunku 3.9. Rysunek 3.9. Logiczny przebieg wykonania instrukcji if-else
98
PHP i MySQL. Witryna WWW oparta na bazie danych
Fragment else instrukcji if-else należy dokleić na końcu fragmentu if w następujący sposób. Listing 3.18. welcome7.php (fragment) $name = $_REQUEST['name']; if ($name == 'Kevin') { echo 'Witamy, o przewspaniały!'; } else { echo 'Witaj na naszej witrynie, ' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '!'; }
Teraz jeśli w formularzu wpisane zostanie imię inne niż Kevin, wyświetlone zostanie zwyczajowe powitanie widoczne na rysunku 3.10. Rysunek 3.10. Warto pamiętać imiona znajomych
Podwójny znak równości (==), użyty tutaj w warunku, jest w języku PHP operatorem porównania, który służy do sprawdzania, czy dwie wartości są sobie równe. Warunki mogą być — oczywiście — dużo bardziej złożone niż proste sprawdzenie, czy dwie wartości są równe. Jak pamiętamy, nasz formularz pozwalał na wprowadzenie zarówno imienia, jak i nazwiska. Jeśli chcielibyśmy wyświetlić specjalny komunikat przeznaczony tylko dla jednej konkretnej osoby, to powinniśmy sprawdzić zarówno wartość imienia, jak i nazwiska. W tym celu należy najpierw utworzyć kopię pliku welcome6.html (który zawiera wersję formularza HTML z dwoma polami) i nazwać ją welcome8.html. Atrybut action znacznika trzeba zmienić w taki sposób, by wskazywał na plik welcome8.html. Następnie należy sporządzić kopię pliku welcome7.php i nadać jej nazwę welcome8.php, po czym zmienić zawarty w niej kod zgodnie ze zmianami wyróżnionymi pogrubioną czcionką na listingu 3.19.
Rozdział 3. ♦ Wprowadzenie do języka PHP
99
Nieszczęścia chodzą parami Należy pamiętać o wpisywaniu podwójnego znaku równości. Błędem powszechnie popełnianym przez początkujących programistów jest wpisywanie warunku, takiego jak poniżej, zawierającego tylko jeden znak równości: if ($name = 'Kevin')
// Brakujący znak równości!
W powyższym warunku użyto operatora przypisania (=), który przedstawiłem w podrozdziale pod tytułem „Zmienne, operatory i komentarze”, zamiast operatora porównania (==). W efekcie zamiast porównania wartości zmiennej $name do ciągu znaków 'Kevin' instrukcja przypisze zmiennej $name wartość 'Kevin'. Ups! Co gorsza, instrukcja if użyje operatora porównania jako warunku, który zostanie uznany za spełniony. Zatem kod warunkowy znajdujący się w instrukcji if zawsze zostanie wykonany, bez względu na to, jaka będzie oryginalna wartość zmiennej $name. Listing 3.19. welcome7.php (fragment) $firstname = $_REQUEST['firstname']; $lastname = $_REQUEST['lastname']; if ($firstname == 'Kevin' and $lastname == 'Yank') { echo 'Witamy, o przewspaniały!'; } else { echo 'Witaj na naszej witrynie, ' . htmlspecialchars($firstname, ENT_QUOTES, 'UTF-8') . ' ' . htmlspecialchars($lastname, ENT_QUOTES, 'UTF-8') . '!'; }
Tak zmodyfikowany warunek będzie spełniony wtedy i tylko wtedy, gdy zmienna $firstname będzie miała wartość Kevin, a zmienna $lastname wartość Yank. Słowo and (operator logiczny „i”) umieszczone w warunku sprawia, że będzie on spełniony tylko wtedy, gdy oba porównania dadzą wartość TRUE (prawda). Podobnym operatorem logicznym jest or („lub”), który sprawia, że cały warunek jest prawdziwy, jeśli choć jeden z dwóch warunków składowych będzie spełniony. Programiści, którzy przyzwyczajeni są raczej do stosowania tych operatorów w formie, w jakiej występują w języku JavaScript czy C (odpowiednio && zamiast and i || zamiast or), mogą bez obaw z nich korzystać — będą działać również w PHP. Na rysunku 3.11 pokazano, że tym razem „do tanga trzeba dwojga” i poprawne podanie w naszym przykładzie tylko imienia lub tylko nazwiska nie wyświetli specjalnej strony powitalnej. Bardziej złożonym warunkom przyjrzymy się wówczas, gdy będą nam potrzebne. Na razie te dwa powinny wystarczyć, by zrozumieć działanie instrukcji if-else. Kolejną strukturą sterującą często wykorzystywaną w języku PHP jest pętla while. Podczas gdy instrukcja if-else umożliwia decydowanie, czy wykonywać określony
100
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 3.11. Ani cienia szansy, moja droga…
zestaw instrukcji w zależności od pewnego warunku, pętla while pozwala wykorzystać warunek do zdefiniowania, ile razy należy powtórzyć wykonanie zestawu określonych instrukcji. Na rysunku 3.12 zilustrowano sposób działania pętli while. Rysunek 3.12. Logiczny przebieg pętli while
Oto sposób, w jaki pętlę while umieszcza się w kodzie źródłowym: while (warunek) { // Instrukcja (bądź instrukcje), które // będą powtarzane po raz kolejny i kolejny // póki warunek będzie spełniony (prawdziwy). }
Pętla while jest więc bardzo podobna do instrukcji if. Różnica polega na sposobie rozpatrywania instrukcji (lub zestawu instrukcji) znajdujących się wewnątrz pętli, jeśli warunek pętli jest spełniony. Zamiast kontynuować wykonywanie dalszych instrukcji skryptu, które następują po zamykającym strukturę nawiasie klamrowym (}), warunek jest wtedy sprawdzany jeszcze raz. Jeśli nadal jest spełniony (daje wartość TRUE), zestaw instrukcji między nawiasami wykonywany jest po raz drugi, potem po raz trzeci
Rozdział 3. ♦ Wprowadzenie do języka PHP
101
i kolejny — jak długo warunek będzie prawdziwy. Natomiast gdy tylko po raz pierwszy warunek okaże się fałszywy (to jest nie zostanie spełniony — nieważne, czy za pierwszym, czy za sto pierwszym wykonaniem pętli), interpreter przeskoczy natychmiast do wykonywania instrukcji następujących po nawiasie zamykającym pętlę while. Takie pętle okazują się bardzo przydatne wszędzie tam, gdzie musimy zająć się długą lista rzeczy (na przykład kawałów zachowanych w bazie danych… podpowiedź, podpowiedź!), na razie jednak zilustrujemy ją prostym przykładem liczenia do dziesięciu. Listing 3.20. count10.php (fragment) $count = 1; while ($count
Plik ten zawiera niemal wyłącznie czysty kod HTML, z wyjątkiem jednego wiersza, który wyświetla wartość zmiennej $output. Jest to ta sama zmienna $output, którą utworzyliśmy w pliku index.php.
8
W innych książkach można napotkać instrukcję include, w której nazwa pliku jest umieszczana w nawiasach — tak samo jakby include była funkcją podobną do funkcji date albo htmlspecialchars, choć tak — oczywiście — nie jest. Użycie nawiasów komplikuje jedynie wyrażenie, którego wynikiem powinna być nazwa pliku, dlatego nie będziemy ich stosować w tej książce. To samo dotyczy instrukcji echo — kolejnej popularnej instrukcji jednowierszowej.
Rozdział 3. ♦ Wprowadzenie do języka PHP
107
W ten właśnie sposób powstał szablon PHP — strona HTML zawierająca niewielki fragment kodu PHP, który do statycznej strony HTML wstawia wartości wygenerowane dynamicznie. Zamiast osadzać złożony kod PHP odpowiedzialny za wygenerowanie tych wartości na stronie, właściwy kod został umieszczony w naszym przykładzie w oddzielnym skrypcie PHP o nazwie index.php. Taki sposób użycia szablonów PHP pozwala na przekazywanie ich mało zorientowanym projektantom stron WWW bez obaw o to, że mogą coś zmienić w kodzie źródłowym. Ponadto łatwiej wówczas skupić się na właściwym kodzie PHP, bez rozpraszania się na otaczający go kod HTML. Sam zawsze nadaję szablonom PHP nazwy zakończone rozszerzeniem .html.php. Wprawdzie dla serwera WWW jest to nadal plik .php, lecz rozszerzenie .html.php służy za przypomnienie, że dany plik zawiera zarówno kod HTML, jak i PHP.
Wiele szablonów, jeden kontroler Zaletą ładowania plików z szablonami PHP za pomocą instrukcji include jest to, że w pojedynczym skrypcie PHP można umieścić wiele instrukcji include i wyświetlać wiele różnych szablonów, zależnie od okoliczności! Skrypt PHP, który odpowiada na żądanie przeglądarki przez wybranie jednego spośród kilku szablonów PHP, jego wypełnienie i odesłanie, jest często określany mianem kontroler. Kontroler zawiera logikę, na podstawie której wyznaczane są szablony wysyłane do przeglądarki internetowej. Zmodyfikujmy jeszcze jeden przykład omawiany już wcześniej, czyli formularz powitalny, w którym użytkownik ma wpisać imię i nazwisko. Najpierw zajmiemy się szablonem PHP formularza. Do tego celu wystarczy wykorzystamy plik welcome8.html. Należy utworzyć katalog o nazwie welcome i zapisać w nim kopię pliku welcome8.html pod nazwą form.html.php. Jedyną zmianą, jaką należy wykonać w tym pliku, jest zmodyfikowanie atrybutu action znacznika . Listing 3.24. count.html.php
>
Przykładowy formularz
Imię:
Nazwisko:
108
PHP i MySQL. Witryna WWW oparta na bazie danych
Jak widać, atrybut action powinien pozostać pusty. Wtedy przeglądarka będzie wiedzieć, że formularz należy odesłać do tego samego adresu URL, z którego został pobrany. W tym przypadku jest to adres URL kontrolera, który zawiera plik szablonu. Przyjrzyjmy się kontrolerowi w tym przykładzie. W katalogu welcome, w którym istnieje już szablon formularza, utwórz skrypt index.php i wpisz w nim następujący kod. Listing 3.25. index.php
include 'welcome.html.php';
Na pierwszy rzut oka kod ten powinien wydać się znajomy. Jest bardzo podobny do kodu skryptu welcome8.php, który napisaliśmy wcześniej. Teraz wyjaśnię, na czym polegają różnice. 1. Najpierw kontroler musi zidentyfikować, czy bieżące żądanie jest
zatwierdzonym formularzem z pliku form.html.php, czy nie. W tym celu sprawdza, czy żądanie zawiera zmienną firstname. Jeżeli wartość zmiennej jest ustawiona, PHP zapisze tę wartość w $_REQUEST['firstname']. Funkcja isset to wbudowana funkcja języka PHP, która wskazuje, czy dana zmienna (albo element tablicy) posiada przypisaną wartość, czy nie. Jeżeli $_REQUEST['firstname'] posiada wartość, wówczas isset($_REQUEST['firstname']) będzie mieć wartość TRUE. Jeżeli natomiast $_REQUEST['firstname'] nie będzie mieć żadnej wartości, funkcja isset($_REQUEST['firstname']) zwróci wartość FALSE.
Rozdział 3. ♦ Wprowadzenie do języka PHP
109
Aby zachować czytelność, chcę umieścić kod wysyłający formularz w kontrolerze. Potrzebna jest zatem instrukcja if, aby sprawdzić, czy $_REQUEST['firstname'] nie jest ustawiona. Do tego celu użyty został operator negacji (!). Umieszczenie operatora negacji przed nazwą funkcji powoduje odwrócenie wartości zwróconej przez tę funkcję z TRUE na FALSE lub z FALSE na TRUE. Jeżeli zatem żądanie nie zawiera zmiennej firstname, wówczas !isset($_REQUEST['firstname']) zwróci TRUE i wykonane zostanie ciało instrukcji if. 2. Jeżeli przedmiotem żądania nie jest wysłany formularz, kontroler dołączy plik
form.html.php, aby go wyświetlić. 3. Jeżeli przedmiotem żądania jest zatwierdzony formularz, wówczas wykonane zostanie ciało instrukcji else.
W kodzie tym z tablicy $_REQUEST odczytywane są wartości firstname i lastname, po czym następuje wygenerowanie odpowiedniego komunikatu powitalnego, zawierającego przesłane imię i nazwisko. 4. Zamiast wyświetlać komunikat powitalny za pomocą instrukcji echo, kontroler przypisuje treść komunikatu zmiennej o nazwie $output. 5. Po wygenerowaniu odpowiedniego komunikatu powitalnego kontroler dołącza
szablon welcome.html.php, który odpowiada za wyświetlenie treści komunikatu. Pozostało już tylko zaimplementować szablon welcome.html.php. Oto jego kod źródłowy. Listing 3.26. welcome.html.php
Przykładowy formularz
I to wszystko! Uruchom przeglądarkę internetową i wpisz adres http://localhost/welcome/ (lub http://localhost:8080/welcome/ albo podobny, jeżeli na swoim serwerze WWW musisz wskazać numer portu). Będziesz musiał podać imię i nazwisko, a gdy zatwierdzisz formularz, ujrzysz komunikat powitalny o odpowiedniej treści. Adres URL powinien pozostać niezmieniony przez cały ten czas. Jedną z korzyści wynikających z utrzymywania tego samego adresu URL przez cały czas, gdy wpisujesz imię i nazwisko oraz wyświetlany jest komunikat powitalny, jest to, że użytkownik może zapisać stronę w zakładkach przeglądarki na dowolnym etapie
110
PHP i MySQL. Witryna WWW oparta na bazie danych
procesu i za każdym razem otrzymać sensowny wynik. Nie ma naprawdę znaczenia, czy w momencie zapisania strony w przeglądarce wyświetlany był na niej formularz, czy komunikat powitalny — za każdym razem, gdy użytkownik ponownie wywoła tę zakładkę, zawsze w przeglądarce pojawi się formularz. W poprzedniej wersji tego przykładu gdy komunikat był wyświetlany przez stronę posiadającą swój własny adres URL, powrót do niej bez wcześniejszego zatwierdzenia formularza prowadził do wyświetlenia niepełnego komunikatu powitalnego o treści „Witamy na naszej witrynie, !”. Dlaczego imię i nazwisko jest zapominane? W rozdziale 9. pokażę, w jaki sposób zapamiętywać imię i nazwisko użytkownika między jego kolejnymi wizytami.
Dajcie mi bazę danych! W tym rozdziale przyjrzeliśmy się, jak działa interpretowany po stronie serwera język skryptowy PHP, i poznaliśmy jego podstawowe elementy: instrukcje, zmienne, operatory, komentarze i struktury sterujące. Przykładowe aplikacje, które analizowaliśmy, były nieskomplikowane, ale mimo to poświęciliśmy trochę czasu na zapewnienie, że ich adresy URL są odpowiednio atrakcyjne oraz szablony HTML generowanych stron nie są zanieczyszczone sterującym nimi kodem PHP. Jak już zapewne zacząłeś podejrzewać, prawdziwa siła PHP tkwi bowiem w setkach (a nawet w tysiącach) wbudowanych funkcji języka, które zapewniają programiście najrozmaitsze możliwości — od sięgania do bazy danych MySQL, poprzez wysyłanie e-maili, aż po dynamiczne generowanie obrazów, a nawet przygotowywanie na poczekaniu plików w formacie Adobe Acrobat PDF. W rozdziale 4., zatytułowanym „Publikowanie w sieci WWW danych przechowywanych w bazie MySQL”, zajmiemy się wbudowanymi funkcjami języka PHP związanymi z systemem MySQL i dowiemy się, jak można publikować na stronach WWW bazę danych opisaną w rozdziale 2., „Wprowadzenie do systemu MySQL”. Lektura tego rozdziału przygotuje podstawy pod to, co jest głównym celem naszej książki — stworzenie kompletnego, opartego na bazie MySQL i języku PHP systemu zarządzania zawartością dla naszej witryny.
Rozdział 4.
Publikowanie w sieci WWW danych przechowywanych w bazie MySQL Nareszcie, właśnie na to czekaliśmy! W tym rozdziale opowiem, jak pobierać informacje przechowywane w bazie danych MySQL i wyświetlać je na stronie WWW, aby mieli do nich dostęp wszyscy użytkownicy. Do tej pory po zainstalowaniu nauczyliśmy się podstaw działania MySQL, systemu zarządzania relacyjnymi bazami danych oraz PHP, języka skryptowego działającego po stronie serwera. Teraz dowiemy się, jak połączyć te narzędzia, by za ich pomocą przygotować witrynę WWW opartą na bazie danych!
Idea działania Zanim przystąpimy do dalszych rozważań, warto przypomnieć sobie, jaki jest nasz główny cel. Mamy do dyspozycji dwa wspaniałe narzędzia: język skryptowy PHP i system zarządzania bazami danych MySQL. Pora teraz na naukę, jak połączyć je ze sobą. Podstawowym celem tworzenia witryny WWW opartej na bazie danych jest przechowywanie zawartości witryny w bazie danych, tak aby można ją było stamtąd pobierać dynamicznie, tworząc na poczekaniu strony WWW, do których użytkownicy witryny zyskają dostęp za pomocą zwykłej przeglądarki internetowej. Tak więc po jednej stronie
112
PHP i MySQL. Witryna WWW oparta na bazie danych
mamy odwiedzającego, który pobiera stronę za pośrednictwem przeglądarki internetowej i spodziewa się otrzymać w zamian standardowy dokument HTML. A po drugiej stronie zawartość witryny, rozproszoną po jednej lub więcej tabelach w bazie danych MySQL, która to baza akceptuje tylko polecenia w formie zapytań SQL. Tak jak zostało to przedstawione na rysunku 4.1, język skryptowy PHP pełni funkcję pośrednika, który potrafi posługiwać się oboma językami. Najpierw przetwarza żądanie strony i pobiera dane z bazy MySQL, używając zapytań SQL, takich jak te, które testowaliśmy na tabeli kawaly w rozdziale 2., „Wprowadzenie do systemu MySQL”. Następnie przygotowuje ładnie sformatowaną stronę HTML, której oczekuje przeglądarka. Rysunek 4.1. Schemat pokazujący, w jaki sposób język PHP pobiera dane z bazy MySQL, by przygotować strony WWW
Aby przedstawić to jeszcze przejrzyściej, wyjaśnię, co dzieje się, gdy użytkownik odwiedza naszą witrynę WWW opartą na bazie danych. 1. Przeglądarka internetowa odwiedzającego żąda strony WWW, wysyłając
standardowy adres URL. 2. Program serwera WWW (zwykle jest to serwer Apache) ustala, że żądany plik
jest skryptem PHP i serwer uruchamia interpreter języka PHP, aby wykonać kod znajdujący się w pliku. 3. Odpowiednie polecenia PHP (na których skupimy się w tym rozdziale) łączą
się z bazą danych MySQL i żądają zawartości, która powinna pojawić się na przygotowywanej stronie WWW. 4. Baza danych MySQL odpowiada, przesyłając skryptowi PHP żądaną zawartość. 5. Skrypt PHP zapisuje pobraną zawartość w jednej lub więcej zmiennych PHP, a następnie za pomocą instrukcji echo umieszcza ją w odpowiednich miejscach
strony WWW. 6. Interpreter języka PHP kończy pracę, zwracając przygotowaną przez siebie
stronę kodu HTML serwerowi WWW. 7. Serwer WWW przesyła tę stronę z kodem HTML do przeglądarki internetowej,
tak jakby to był zwykły plik HTML. Nie przesyła jednak gotowego, statycznego pliku HTML, lecz kod zwrócony przez interpreter języka PHP.
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
113
Łączenie się z bazą MySQL za pomocą PHP Zanim spróbujemy pobrać z bazy danych MySQL treść, która zostanie opublikowana na stronie WWW, musimy dowiedzieć się, jak wewnątrz skryptu PHP ustanowić połączenie z systemem MySQL. Jak pamiętamy, w rozdziale 2., „Wprowadzenie do systemu MySQL”, korzystaliśmy z programu mysql, który pozwalał nawiązywać takie połączenie wprost z wiersza poleceń. PHP potrafi się łączyć bezpośrednio z serwerem MySQL, podobnie jak czyni to program mysql, ponieważ obsługa łączenia się z serwerem MySQL jest bezpośrednio wbudowana w ten język w postaci biblioteki funkcji. Połączenie z serwerem MySQL tworzy wbudowana funkcja mysql_connect. mysqli_connect(nazwa_komputera, nazwa_użytkownika, hasło)
Jak już wspomniano w rozdziale 3., gdy funkcje PHP są przywoływane, zazwyczaj zwracają jakąś wartość. I tak przedstawiona tutaj funkcja mysqli_connect zwraca tak zwany identyfikator połączenia, który pozwala odróżnić właśnie ustanowione połączenie. Ponieważ z tego połączenia zamierzamy korzystać później, powinniśmy tę wartość zachować. Oto praktyczny przykład takiego polecenia połączenia się z serwerem MySQL: $link = mysqli_connect('localhost', 'root', 'hasło');
Jak już wspomniano, wartości tych trzech parametrów funkcji mogą się różnić w zależności od serwera MySQL, z którym się łączymy. W najlepszym przypadku konieczne będzie wstawienie właściwego hasła, które zdefiniowałeś dla użytkownika root. Warto zwrócić uwagę na to, że wartość zwrócona przez funkcję mysqli_connect przechowywana jest w zmiennej $link. Ponieważ serwer MySQL jest programem zupełnie niezależnym od serwera WWW, musimy uwzględnić sytuację, w której serwer będzie z jakiegoś powodu niedostępny lub nieosiągalny, na przykład dlatego, że wystąpiły jakieś problemy z połączeniem sieciowym lub użyliśmy niewłaściwej kombinacji nazwy użytkownika i hasła. W takich przypadkach funkcja mysqli_connect nie zwróci identyfikatora połączenia (bo połączenie nie zostało nawiązane), lecz wartość FALSE (fałsz). Dzięki temu możemy skorzystać z instrukcji if i odpowiednio zareagować, gdy nie uda się nawiązać połączenia. Listing 4.1. connect/index.php (fragment) $link = mysqli_connect('localhost', 'root', 'haslo'); if (!$link) { $output = 'Nie można się połączyć z serwerem bazy danych.'; include 'output.html.php'; exit(); }
114
PHP i MySQL. Witryna WWW oparta na bazie danych
W warunku instrukcji if znak wykrzyknika jest operatorem negacji (ang. negation operator); przy jego użyciu warunek jest spełniony, gdy zmienna $link ma wartość FALSE (czyli gdy próba nawiązania się nie powiodła). Dzięki temu, jeśli połączenie zostanie nawiązane, identyfikator połączenia przechowywany w zmiennej $link zostanie rozpoznany jako wartość TRUE, a !$link będzie mieć wartość FALSE. W skrócie mówiąc, ciało instrukcji if zostanie wykonane jedynie wówczas, gdy nawiązanie połączenia się nie powiedzie. Wewnątrz instrukcji if zmiennej $output jest przypisywana treść komunikatu informującego o naturze problemu. Następnie dołączamy szablon output.html.php. Jest to ogólny szablon, który po prostu wyświetla wartość zmiennej $output. Listing 4.2. connect/output.html.php
Dane wynikowe PHP
Na końcu, po wyświetleniu treści komunikatu ciało instrukcji if wywołuje wbudowaną funkcję exit. Funkcja exit jest pierwszym w tej książce przykładem funkcji, którą można przywoływać bez żadnych parametrów. Jeśli przywołamy ją, nie podając żadnych parametrów, PHP przerwie w tym miejscu odczytywanie strony. Zyskujemy zatem pewność, że reszta kodu zawartego w kontrolerze (którego wykonanie w większości zależy od tego, czy uda się połączyć z bazą danych) nie zostanie wykonana, w sytuacji gdy nawiązanie połączenia z bazą danych się nie uda. Przy założeniu, że uda się nawiązać połączenie z bazą, zanim będzie można je wykorzystać, konieczne będzie jego odpowiednie skonfigurowanie. Jak wspomniałem w rozdziale 3., na witrynach WWW najlepiej stosować kodowanie znaków UTF-8, aby zmaksymalizować zakres znaków dostępnych dla użytkownika w trakcie wypełniania formularzy prezentowanych na witrynie. Domyślnie gdy PHP łączy się z serwerem MySQL, włączane jest prostsze kodowanie ISO-8859-1 zamiast UTF-8. Trzeba zatem dodatkowo skonfigurować połączenie nawiązane za pomocą mysqli_connect przez wywołanie kolejnej wbudowanej funkcji PHP o nazwie mysqli_set_charset: mysqli_set_charset($link, 'utf-8');
Skorzystaliśmy ze zmiennej $link, przechowującej identyfikator połączenia z bazą danych MySQL, by poinformować funkcję, z którego połączenia z bazą danych powinna
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
115
skorzystać. Funkcja zwraca wartość TRUE, jeśli jej działanie się powiedzie, i FALSE, gdy pojawią się jakieś błędy. Podobnie jak poprzednio, wyrazem rozwagi będzie skorzystanie z instrukcji if, aby zareagować na ewentualne błędy. Listing 4.3. connect/index.php (fragment) if (!mysqli_set_charset($link, 'utf8')) { $output = 'Nie można ustanowić kodowania dla połączenia z bazą danych.'; include 'output.html.php'; exit(); }
Warto zauważyć, że tym razem — zamiast przypisywać zmiennej wartość zwróconą przez funkcję i potem sprawdzać, czy jest ona prawdą, czy fałszem — po prostu wykorzystałem w warunku samo przywołanie funkcji. Na pozór wygląda to trochę nietypowo, ale jest to dość często używany skrótowy zapis. Aby ustalić, czy warunek jest spełniony, czy nie, interpreter PHP wykona funkcję, a potem sprawdzi zwróconą przez nią wartość — czyli zrobi właśnie to, na czym nam zależy. Podobnie jak w rozdziale 2., gdy połączenie z serwerem MySQL nawiązywane jest przez program mysql, wówczas od razu po nawiązaniu połączenia zwykle następuje wybór bazy danych, na której mają być wykonywane dalsze polecenia. Powiedzmy, że chcemy pracować na bazie danych ijdb, która powstała w rozdziale 2. Wybór odpowiedniej bazy danych w PHP to kwestia wywołania kolejnej funkcji: mysqli_select_db($link, 'ijdb');
Funkcja mysqli_select_db wybiera wskazaną bazę danych ('ijdb') w ramach wskazane połączenia z bazą danych ($link). Podobnie jak poprzednio wyrazem rozwagi będzie skorzystanie z instrukcji if, aby zareagować na ewentualne błędy. Listing 4.4. connect/index.php (fragment) if (!mysqli_select_db($link, 'ijdb')) { $output = 'Nie znalezionio bazy danych ijdb.'; include 'output.html.php'; exit(); }
Aby zakończyć przykładowy skrypt, trzeba wyświetlać również komunikat statusu, który będzie informował, że wszystkie operacje zakończyły się pomyślnie. Oto pełen kod kontrolera. Listing 4.5. connect/index.php
Uruchom przykładowy skrypt w przeglądarce (jeśli umieściłeś pliki index.php i output. html.php w katalogu o nazwie connect na serwerze WWW, adres URL będzie miał postać http://localhost/connect/). Jeżeli serwer MySQL jest uruchomiony i działa poprawnie, a wszystkie wykonane czynności zakończyły się powodzeniem, w przeglądarce powinna pojawić się informacja widoczna na rysunku 4.2. Rysunek 4.2. Informacja o skutecznym nawiązaniu połączenia
Jeżeli PHP nie zdoła połączyć się z serwerem MySQL albo podany użytkownik i hasło okażą się nieprawidłowe, zamiast powyższego komunikatu wyświetlony zostanie komunikat podobny do widocznego na rysunku 4.3. Aby upewnić się, że mechanizm obsługi błędów działa prawidłowo, najlepiej wprowadzić w haśle błąd literowy i przetestować działanie kodu. Jeżeli PHP połączy się z serwerem MySQL, lecz nie znajdzie bazy danych ijdb, wówczas w przeglądarce pojawi się komunikat podobny do widocznego na rysunku 4.4. Ponownie warto przetestować poprawność działania skryptu przez celowe wprowadzenie błędu literowego w nazwie bazy danych.
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
117
Rysunek 4.3. Błąd w nawiązywaniu połączenia
Jaki błąd PHP? Zależnie od konfiguracji interpretera PHP na serwerze WWW, pierwszy akapit tekstu widocznego na rysunku 4.3 może, lecz nie musi, się wyświetlić. Jeżeli PHP został skonfigurowany tak, by wyświetlał komunikaty o błędach, wówczas komunikat ostrzeżenia zostanie pokazany automatycznie. Tak szczegółowa informacja o błędzie jest nieocenioną pomocą w trakcie diagnozowania źródeł problemów napotkanych w zaimplementowanym kodzie źródłowym. Gdy jednak witryna zostanie przeniesiona i udostępniona w środowisku produkcyjnym w sieci WWW, zwykle wyłącza się wyświetlanie tego rodzaju komunikatów o błędach. Jeżeli samodzielnie zainstalowałeś serwer Apache, prawdopodobnie komunikat ostrzeżenia zostanie wyświetlony. Jeśli natomiast używasz serwera Apache instalowanego z pakietu (takiego jak WampServer albo MAMP), wówczas mechanizm wyświetlania błędów PHP może być domyślnie wyłączony. Aby wyświetlić błędy (które są pomocne zwłaszcza na etapie prac programistycznych, gdy trzeba zidentyfikować przyczynę usterki), należy otworzyć plik php.ini na serwerze i opcji display_errors przypisać wartość On. Plik php.ini na serwerze WampServer jest dostępny z poziomu paska narzędzi systemowych. Z kolei plik php.ini na serwerze MAMP znajduje się w folderze /Applications/MAMP/conf/php5. Rysunek 4.4. Błąd połączenia
Gdy połączenie będzie nawiązane i wybrana zostanie baza danych, będziesz mógł rozpocząć korzystanie z danych zapisanych w bazie.
118
PHP i MySQL. Witryna WWW oparta na bazie danych
PHP rozłącza się automatycznie Zastanawiasz się pewnie, co się stanie z połączeniem z serwerem MySQL, gdy skrypt zakończy działanie. PHP posiada funkcję, która odpowiada za zakończenie połączenia z serwerem (mysqli_close), jednak i tak wszystkie otwarte połączenia z bazą danych, które nie będą już więcej potrzebne, zostaną zamknięte automatycznie. Wystarczy więc pozwolić PHP samodzielnie sprzątać po sobie.
Wysyłanie zapytań SQL za pomocą języka PHP W rozdziale 2., „Wprowadzenie do systemu MySQL”, łączyliśmy się z serwerem bazy danych MySQL za pomocą programu o nazwie mysql, który pozwalał na wpisywanie zapytań (poleceń) SQL i natychmiastowe oglądanie ich wyników. W języku PHP istnieje całkiem podobny mechanizm, mianowicie funkcja mysqli_query: mysqli_query(identyfikator_połączenia, zapytanie)
Tutaj zapytanie będzie po prostu łańcuchem tekstu zawierającym polecenie SQL, które chcemy wykonać. Podobnie jak w przypadku funkcji mysqli_select_db, trzeba również wskazać identyfikator połączenia zwrócony przez funkcję mysqli_connect. To, co ta funkcja zwróci, zależy już od rodzaju wysłanego zapytania. W większości zapytań języka SQL funkcja mysql_query zwraca wartość TRUE lub FALSE, by zasygnalizować (odpowiednio), czy zapytanie zostało wykonane z powodzeniem, czy też nie. Przeanalizujmy następujący przykład, w którym spróbujemy utworzyć tabelę kawal, taką jak w rozdziale 2., „Wprowadzenie do systemu MySQL”. Listing 4.5. createtable/index.php (fragment) $sql = 'CREATE TABLE kawal ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, tekstkawalu TEXT, datakawalu DATE NOT NULL ) DEFAULT CHARACTER SET utf8'; if (!mysqli_query($link, $sql)) { $output = 'Nie udało się utworzyć tabeli kawal: ' . mysqli_error($link); include 'output.html.php'; exit(); } $output = 'Udało się utworzyć tabelę kawal.'; include 'output.html.php';
Warto zaznaczyć, że również w tym przypadku zastosowaliśmy instrukcję if, aby obsłużyć ewentualne błędy powstałe w trakcie wykonywania zapytania. W przykładzie użyto
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
119
także funkcji mysqli_error, aby odczytać szczegółowy komunikat o błędzie wygenerowany przez serwer MySQL. Na rysunku 4.5 przedstawiono komunikat błędu wyświetlony, w sytuacji gdy tabela kawal będzie już istnieć. Rysunek 4.5. Zapytanie CREATE TABLE nie powiodło się, ponieważ tabela już istnieje
W przypadku zapytań DELETE, INSERT i UPDATE (służą one do modyfikowania danych) system MySQL notuje również liczbę wierszy tabeli (pozycji), które zostały zmienione przez zapytanie. Rozważmy takie zapytanie SQL, którego używaliśmy już w rozdziale 2., „Wprowadzenie do systemu MySQL”, by zmienić daty wszystkich kawałów, zawierających słowo „kurczak”. Listing 4.6. createtable/updatechicken.php (fragment) $sql = 'UPDATE kawal SET datakawalu="2010-04-01" WHERE tekstkawalu LIKE "%kurczak%"'; if (!mysqli_query($link, $sql)) { $output = 'Błąd w trakcie wykonywania uaktualnienia: ' . mysqli_error($link); include 'output.html.php'; exit(); }
Kiedy wykonamy to zapytanie, będziemy mogli skorzystać z funkcji mysql_affected_ ´rows, by poznać liczbę wierszy, które zostały zmienione przez to zapytanie UPDATE. Listing 4.7. createtable/updatechicken.php (fragment) $output = 'Uaktualniono ' . mysqli_affected_rows($link) . ' wiersz(y).'; include 'output.html.php';
Na rysunku 4.6 przedstawiono efekt uaktualnienia wykonany przez powyższy skrypt przy założeniu, że w bazie dowcipów znajduje się tylko jeden dowcip, w którym występuje słowo „kurczak”. Gdy odświeżysz stronę, aby ponownie wykonać to samo zapytanie, powinieneś ujrzeć komunikat widoczny na rysunku 4.7. Informuje, że żaden wiersz nie został zmieniony, ponieważ nowa data, która ma zostać przypisana dowcipom, jest taka sama jak data już wcześniej im przypisana.
120
PHP i MySQL. Witryna WWW oparta na bazie danych
Rysunek 4.6. Liczba uaktualnionych wierszy w bazie danych jest wyświetlana na stronie
Rysunek 4.7. MySQL od razu powie, że marnujesz czas
Zapytania SELECT traktowane są trochę inaczej, ponieważ pobierają bardzo dużo danych i język PHP musi dostarczać jakichś sposobów obsługiwania tych informacji.
Obsługa zbiorów wyników zapytania SELECT W większości zapytań SQL funkcja mysqli_query zwracać będzie albo wartość TRUE (prawda, w przypadku sukcesu), albo FALSE (fałsz, w razie niepowodzenia). Gdy jednak wykonujemy zapytanie SELECT, potrzeba więcej informacji. Jak pamiętamy, zapytania SELECT służą do oglądania danych przechowywanych w bazie danych. Dlatego też, oprócz informacji, czy zapytanie zakończyło się powodzeniem, czy nie, język PHP musi również w jakiś sposób odebrać zwrócone wyniki zapytania. Zatem w przypadku zapytania SELECT funkcja mysqli_query zwraca zbiór wyników (ang. result set), który zawiera wszystkie wiersze (pozycje, rekordy) zwrócone przez zapytanie. Jeśli zapytanie z jakichś powodów się nie powiedzie, zwracana jest wartość FALSE.
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
121
Listing 4.8. listjokes/index.php (fragment) $result = mysqli_query($link, 'SELECT tekstkawalu FROM kawal'); if (!$result) { $error = 'Błąd odczytu kawałów: ' . mysqli_error($link); include 'error.html.php'; exit(); }
Podobnie jak poprzednio, błędy są wyświetlane przy użyciu bardzo prostego szablonu. Listing 4.9. listjokes/error.html.php
Błąd PHP
Przy założeniu, że w trakcie przetwarzania nie pojawił się żaden błąd, przedstawiony kod zapisze w zmiennej $result zbiór wyników. Zbiór zawiera teksty wszystkich kawałów przechowywanych w tabeli kawal. Ponieważ nie ma praktycznie żadnych ograniczeń dotyczących liczby dowcipów przechowywanych w bazie, zwrócony zbiór wyników może być całkiem pokaźny. Jak już wspomniano w rozdziale 3., pętla while jest bardzo przydatną strukturą sterującą, gdy musimy pracować z dużymi zestawami danych. Oto szkic kodu, który umożliwi przetwarzanie jeden po drugim kolejnych wierszy w zbiorze wyników: while ($row = mysqli_fetch_array($result)) { // przetwarzaj odpowiednio wiersz... }
Warunek wykorzystany w pętli while nie przypomina warunków, z którymi zetknęliśmy się do tej pory. Dlatego poświęcę mu kilka słów wyjaśnienia. Przyjrzyjmy się warunkowi tak, jakby był osobną instrukcją: $row = mysqli_fetch_array($result);
Funkcja mysqli_fetch_array przyjmuje jako parametr liczbę identyfikującą zbiór wyników (w tym przypadku przechowywaną w zmiennej $result) i zwraca kolejny wiersz ze zbioru wyników w postaci tablicy (więcej informacji na temat tablic można znaleźć
122
PHP i MySQL. Witryna WWW oparta na bazie danych
w rozdziale 3., „Wprowadzenie do języka PHP”). Gdy wreszcie funkcja mysqli_fetch_ ´array dojdzie w zbiorze wyników do końca i nie znajdzie kolejnego wiersza, zwróci wartość FALSE. Powyższa instrukcja przypisuje zmiennej wiersza $row pewną wartość, ale jednocześnie cała instrukcja przyjmuje tę samą wartość. To pozwala nam użyć tej instrukcji jako warunku w pętli while. Ponieważ pętla while będzie wykonywana dopóty, dopóki warunek nie przyjmie wartości FALSE, pętla ta będzie wykonywana tak długo, jak długo funkcja mysql_fetch_array zdoła pobierać kolejne wiersze, a za każdym nawrotem pętli zmiennej $row będzie przypisywana wartość kolejnego wiersza. Pozostaje nam jedynie znaleźć sposób na pobieranie w każdym nawrocie pętli wartości zapisanych w zmiennej tablicowej $row. Wiersze wyników zwracane przez funkcję mysqli_fetch_array przechowywane są w postaci tablic asocjacyjnych. Indeksami takiej tablicy będą nazwy kolejnych kolumn tabeli zwracanych w zbiorze wyników. Jeśli zmienna $row reprezentuje pojedynczy wiersz z naszego zbioru wyników, to zapis $row['tekstkawalu'] odwoływać się będzie do wartości kolumny tekstkawalu w tym wierszu. Celem tego kodu jest odczytanie treści wszystkich kawałów, aby wyświetlić je w szablonie PHP. Najlepszym sposobem na wykonanie tego zadania jest zapisywanie każdego kawału jako nowego elementu tablicy $jokes. Listing 4.10. listjokes/index.php (fragment) while ($row = mysqli_fetch_array($result)) { $jokes[] = $row['joketext']; }
Po odczytaniu kawałów z bazy danych można je przekazać do szablonu PHP (jokes.html. php), aby całość wyświetlić na stronie. Poniżej został przedstawiony kompletny kod strony kontrolera dla omawianego przykładu. Listing 4.11. listjokes/index.php
Aby doprowadzić przykład do końca, pozostało już tylko zaimplementować szablon jokes.html.php. W szablonie tym po raz pierwszy będzie trzeba wyświetlać zawartość tablicy, a nie tylko wartość zwykłej zmiennej. Najprostszym sposobem przetwarzania tablicy w PHP jest użycie pętli. Poznaliśmy już pętle while i for. Kolejnym rodzajem pętli — szczególnie przydatnej do przetwarzania tablicy — jest pętla foreach: foreach (tablica as $element) { // przetworzenie pojedynczego $elementu }
W nawiasach na początku pętli foreach zamiast warunku znajduje się tablica, a po niej słowo kluczowe as, po którym następuje nazwa nowej zmiennej. Nowej zmiennej będzie po kolei przypisywany kolejny element tablicy. Ciało pętli jest następnie wykonywane po jednym razie dla każdego elementu tablicy. W każdej iteracji element jest przypisywany zmiennej, więc kod ciała ma do niego bezpośredni dostęp. W szablonie PHP powszechną praktyką jest używanie pętli foreach do wyświetlenia kolejnych elementów tablicy. Oto sposób, w jaki można skonstruować pętlę foreach dla tablicy kawałów $jokes:
124
PHP i MySQL. Witryna WWW oparta na bazie danych
Uzbrojeni w nowe narzędzie, możemy już zaimplementować szablon, który będzie wyświetlał listę kawałów. Listing 4.12. listjokes/jokes.html.php
Lista kawałów
Oto wszystkie kawały przechowywane w bazie danych:
Każdy kawał jest wyświetlany w oddzielnym akapicie (
), który z kolei znajduje się w bloku cytatu (), ponieważ cytujemy autora każdego kawału prezentowanego na stronie. Niektóre kawały mogą przez przypadek zawierać znaki, które mogłyby zostać zinterpretowane jako kod HTML (na przykład znaki albo &), dlatego trzeba użyć funkcji htmlspecialchars, aby zapewnić, że znaki te zostaną przekształcone w elementy języka HTML (czyli odpowiednio i &), żeby zostały prawidłowo wyświetlone. Na rysunku 4.8 pokazano wygląd strony po dodaniu do naszej bazy kilku kawałów.
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
125
Rysunek 4.8. Wszystkie perełki z mojego repertuaru w jednym miejscu!
Wstawianie danych do bazy W tej części rozdziału zostaną przedstawione narzędzia, które umożliwiają odwiedzającym dodawanie kolejnych kawałów do naszej bazy danych. Aby umożliwić odwiedzającym dodawanie nowych kawałów do bazy, oczywiście potrzebny nam będzie odpowiedni formularz. Oto kod formularza, który spełni to zadanie. Listing 4.13. addjoke/form.html.php (fragment)
Dodawanie kawału
Wpisz treść kawału:
126
PHP i MySQL. Witryna WWW oparta na bazie danych
Tak jak poprzednio, formularz po zatwierdzeniu wywoła ten sam skrypt PHP, który ten formularz wygenerował, czyli skrypt kontrolera index.php. Nietrudno jednak zauważyć, że zamiast pozostawić atrybut action bez wartości (""), przypisano mu znak zapytania ?. Jak zaraz zobaczymy, adres URL, który wywołuje przykładowy formularz, będzie zawierał ciąg zapytania, zaś przypisanie atrybutowi action wartości ? wytnie ciąg zapytania z adresu URL, gdy użytkownik zatwierdzi formularz. Na rysunku 4.9 pokazano, jak formularz ten będzie wyglądać w oknie przeglądarki. Rysunek 4.9. Kolejna perełka humoru wprowadzona do bazy
Po zatwierdzeniu formularza do żądania zostanie dodana zmienna o nazwie joketext, która będzie zawierać tekst kawału wpisanego w polu tekstowym. Zmienna ta pojawi się w tablicach $_POST i $_REQUEST automatycznie generowanych przez PHP. Dołączmy formularz z poprzednim przykładem, który wyświetlał listę kawałów przechowywanych w bazie danych. Nad listą kawałów trzeba dodatkowo wyświetlić łącze zachęcające użytkownika do dodania kawału. Listing 4.14. addjoke/jokes.html.php (fragment)
Dodaj kawał
Oto wszystkie kawały przechowywane w bazie danych:
Nowe łącze wskazuje, podobnie jak formularz, na ten sam skrypt PHP, który generuje stronę. Tym razem jednak dodawany jest również ciąg zapytania (?addjoke), który wskazuje, że użytkownik chce dodać nowy kawał. Kontroler wykryje ciąg zapytania i zinterpretuje go jako sygnał nakazujący wyświetlenie formularza „Dodawanie kawału” zamiast listy wszystkich kawałów. Teraz w kodzie kontrolera możemy wprowadzić odpowiednie zmiany. Listing 4.15. addjoke/index.php (fragment) if (isset($_GET['addjoke'])) { include 'form.html.php';
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
127
exit(); }
Otwierająca instrukcja if sprawdza, czy ciąg zapytania zawiera zmienną o nazwie addjoke. W ten właśnie sposób kontroler wykrywa, że użytkownik kliknął łącze służące do dodawania nowych kawałów. Nawet jeśli w ciągu zapytania (?addjoke) dla zmiennej addjoke nie wskazano żadnej wartości, sama zmienna i tak jest tworzona i można ją wykryć przy użyciu polecenia isset($_GET['addjoke']). Gdy zmienna zostanie wykryta, dołączony plik form.html.php spowoduje wyświetlenie formularza. Następnie wykonywana jest instrukcja exit. Kiedy użytkownik wypełni formularz i zatwierdzi go, do kontrolera zostanie wysłane kolejne żądanie. Zostanie ono wykryte przez sprawdzenie, czy ustawiony jest element $_POST['joketext']. Listing 4.16. addjoke/index.php (fragment) if (isset($_POST['joketext'])) {
Aby zatwierdzony kawał wstawić do bazy danych, trzeba wykonać zapytanie INSERT. Wykorzystuje ono wartość przechowywaną w polu $_POST['tekstkawalu'], by umieścić odpowiedni tekst w kolumnie tekstkawalu tabeli kawal. Odpowiedni kod może wyglądać następująco: $sql = 'INSERT INTO kawal SET tekstkawalu="' . $joketext . '", datakawalu="dzisiejsza data"';
Tak skonstruowany kod posiada jednak bardzo istotną wadę. Otóż, zawartość zmiennej $_POST['tekstkawalu'] zależy wyłącznie od użytkownika, który zatwierdza formularz. Jeżeli będzie to złośliwy użytkownik i wpisze w formularzu odpowiednie zapytanie języka SQL, wówczas skrypt wykona to zapytanie na serwerze bazy danych MySQL. Tego typu atak to tak zwane wstrzyknięcie kodu SQL (ang. SQL injection attack) i w pierwszych latach rozwoju PHP była to luka bezpieczeństwa najczęściej wykorzystywana na witrynach zaimplementowanych w PHP. Ataki zaczęły siać na tyle duże spustoszenie, że zespół rozwijający PHP dodał do języka kilka wbudowanych mechanizmów chroniących przed wstrzykiwaniem kodu SQL. Mechanizmy te w wielu instalacjach PHP pozostają domyślnie włączone. Są to tak zwane magiczne apostrofy (ang. magic quotes), a sam mechanizm ochronny działa w ten sposób, że PHP automatycznie analizuje wszystkie wartości przesłane przez przeglądarkę i przed każdym potencjalnie niebezpiecznym znakiem wstawia znak odwrotnego ukośnika (\). Potencjalnie niebezpieczne znaki, a takim jest na przykład apostrof, mogą spowodować bardzo poważne problemy, gdy znajdą się w kodzie SQL. Jednak mechanizm magicznych cudzysłowów ma tę poważną wadę, że sprawia tyle samo problemów, ilu problemom zapobiega. Przede wszystkim znaki identyfikowane jako niebezpieczne są takimi tylko w niektórych okolicznościach; podobnie rzecz ma się
128
PHP i MySQL. Witryna WWW oparta na bazie danych
z samą metodą ich neutralizacji (czyli poprzedzaniem ich odwrotnym ukośnikiem). Zależnie od sposobu kodowania znaków zastosowanego na witrynie oraz używanego na serwerze baz danych, wykorzystane w tym mechanizmie metody działania mogą wręcz okazać się całkiem nietrafione. Gdy wartość przekazana w zatwierdzonym zapytaniu zostanie wykorzystana do celów innych niż tworzenie zapytania SQL, umieszczone w niej odwrotne ukośniki mogą okazać się bardzo problematyczne. Wspomniałem już o tym w rozdziale 2., gdzie w przykładzie z komunikatem powitalnym mechanizm magicznych apostrofów spowodowałby wstawienie odwrotnego ukośnika w nazwisku użytkownika zawierającym znak apostrofu. Mówiąc w skrócie, magiczne apostrofy okazały się na tyle złym rozwiązaniem, że w wersji PHP 6 planuje się jego usunięcie. Natomiast do tego czasu trzeba się zmagać z problemami występującymi w kodzie. Najprostszym sposobem jest wykrywanie, czy na serwerze WWW magiczne apostrofy są włączone, czy nie, a jeśli są — wycofanie zmian wprowadzonych przez ten mechanizm w przesłanych wartościach1. Na szczęście, w podręczniku języka PHP2 można znaleźć fragment kodu, który wykonuje taką operację. Listing 4.17. addjoke/index.php (fragment) if (get_magic_quotes_gpc()) { function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; } $_POST = array_map('stripslashes_deep', $_POST); $_GET = array_map('stripslashes_deep', $_GET); $_COOKIE = array_map('stripslashes_deep', $_COOKIE); $_REQUEST = array_map('stripslashes_deep', $_REQUEST); }
Nie warto tracić czasu na próbę zrozumienia, co dokładnie dzieje się w tym kodzie. Aby kod był jak najkrótszy, zastosowano w nim kilka zaawansowanych mechanizmów języka PHP, których jeszcze nie poznaliśmy, a dwa z nich wręcz wykraczają poza zakres tej książki. Lepiej po prostu umieścić kod na początku skryptu kontrolera, a także w każdym innym skrypcie PHP, do którego trafiają dane wejściowe pochodzące od użytkownika w postaci zmiennych zapytania albo zatwierdzonego formularza (bądź też, o czym
1
Mechanizm magicznych apostrofów można wyłączyć (i oszczędzić w ten sposób serwerowi znacznej ilości pracy) przez przypisanie opcji magic_quotes_gpc w pliku php.ini wartości Off. Aby jednak zagwarantować, że kod będzie nadal działał poprawnie, gdy mechanizm zostanie włączony, trzeba w kodzie i tak zawrzeć odpowiednie polecenia.
2
http://www.php.net/manual/en/security.magicquotes.disabling.php
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
129
dowiemy się w rozdziale 9., jako plik cookie przeglądarki). Od razu też zastrzegam, że od tego momentu będę przypominał ten kod zawsze, gdy będzie potrzebny dla celów przykładu3. Po wyeliminowaniu szkód poczynionych przez magiczne cudzysłowy trzeba odpowiednio przygotować wartości, które rzeczywiście mają zostać użyte w zapytaniu SQL. Tak jak funkcja htmlspecialchars służy do odpowiedniego przetworzenia wartości pochodzących od użytkownika i przeznaczonych do wyświetlenia w kodzie HTML, tak PHP udostępnia również funkcję przygotowującą dane od użytkownika w taki sposób, by bezpiecznie można było je umieścić w zapytaniu SQL. Funkcja ta nosi nazwę mysqli_real_escape_string. Nazwa może nie jest szczególnie elegancka, ale sama funkcja się sprawdza. Oto sposób jej użycia: $joketext = mysqli_real_escape_string($link, $_POST['joketext']); $sql = 'INSERT INTO kawal SET tekstkawalu="' . $joketext . '", datakawalu="dzisiejsza data"';
W przedstawionym kodzie najpierw skorzystano z funkcji mysqli_real_escape_string, aby przypisać „bezpieczną” wersję zawartości elementu $_POST['joketext'] nowej zmiennej $joketext. Następnie zmiennej $joketext użyto do wstawienia danej pochodzącej od użytkownika do zapytania INSERT jako wartości w kolumnie tekstkawalu. Pytanie, jakie się nasuwa w przypadku tego kodu, dotyczy sposobu przypisania dzisiejszej daty polu datakawalu. Można by napisać jakiś efektowny kod PHP, aby wygenerować dzisiejszą datę w formacie RRRR-MM-DD wymaganym przez MySQL. Okazuje się jednak, że sam MySQL udostępnia odpowiednią funkcję o nazwie CURDATE: $joketext = mysqli_real_escape_string($link, $_POST['joketext']); $sql = 'INSERT INTO kawal SET tekstkawalu="' . $joketext . '", datakawalu=CURDATE()';
Wykorzystujemy tutaj funkcję CURDATE() serwera MySQL, by przypisać kolumnie datakawalu bieżącą datę. System MySQL udostępnia wiele takich przydatnych funkcji, ale omówimy je dopiero wtedy, kiedy będą nam potrzebne. Dokładny opis większości funkcji oferowanych przez system MySQL można znaleźć w dodatku B, „Funkcje MySQL”. Po wypracowaniu ostatecznej wersji zapytania, możemy dokończyć kod instrukcji if, którą zaczęliśmy pisać wcześniej i która obsługuje zatwierdzanie formularza „Dodawanie kawału”. W tym celu można wykonać zapytanie INSERT i użyć funkcji mysqli_query. Listing 4.17. addjoke/index.php (fragment) if (isset($_POST['joketext'])) { $joketext = mysqli_real_escape_string($link, $_POST['joketext']); $sql = 'INSERT INTO kawal SET 3
W rozdziale 6. pokażę, w jaki sposób radzić sobie z sytuacją, gdy kod neutralizujący działanie magicznych apostrofów trzeba będzie wielokrotnie wstawiać w kodzie kontrolera.
130
PHP i MySQL. Witryna WWW oparta na bazie danych tekstkawalu="' . $joketext . '", datakawalu=CURDATE()'; if (!mysqli_query($link, $sql)) { $error = 'Błąd w trakcie dodawania kawału: ' . mysqli_error($link); include 'error.html.php'; exit(); }
}
header('Location: .'); exit();
Ale chwila! W przedstawionej instrukcji if zastosowano jeszcze jedną sztuczkę. Gdy nowy kawał zostanie już zapisany w bazie, wówczas — zamiast znowu wyświetlać szablon PHP — powinniśmy przekierować przeglądarkę użytkownika z powrotem do listy kawałów. W ten sposób użytkownicy od razu będą mogli zobaczyć, że znajduje się wśród nich również dodany kawał. Odpowiadają za to dwa ostatnie wiersze kodu, wyróżnione pogrubioną czcionką. Aby osiągnąć zamierzony rezultat, w pierwszym odruchu zwykle przychodzi myśl, aby po dodaniu nowego dowcipu do bazy danych — zamiast wyświetlać ponownie szablon PHP — kontroler odczytywał ponownie listę kawałów i wyświetlał ją przy użyciu szablonu jokes.html.php. Jednak wiąże się z tym pewien problem. Otóż, z perspektywy przeglądarki strona wynikowa będzie efektem zatwierdzenia formularza „Dodawanie kawału”. Gdyby wówczas użytkownik odświeżył stronę, przeglądarka ponownie zatwierdziłaby formularz i do bazy danych zostałaby wstawiona nowa kopia tego samego kawału! Rzadko jest to pożądane zachowanie. Przeglądarka powinna potraktować uaktualnioną listę kawałów jak zwykłą stronę WWW, którą można odświeżyć bez ponownego zatwierdzenia formularza. W tym celu odpowiedź na zatwierdzenie formularza powinna zawierać przekierowanie HTTP4 (ang. HTTP redirect) — specjalną odpowiedź, informację dla przeglądarki: „Strona, której szukasz, jest tutaj”. Funkcja PHP o nazwie header służy do wysyłania tego rodzaju specjalnych odpowiedzi do serwera. Pozwala na umieszczanie w odpowiedzi przeznaczonej dla serwera specjalnych nagłówków (ang. headers). Aby zasygnalizować przekierowanie, trzeba wraz z adresem URL strony, do którego należy skierować przeglądarkę, przesłać nagłówek Location: header('Location: adres URL');
W naszym przykładzie przeglądarka ma zostać odesłana do tej samej strony, czyli do kontrolera. Jednak zamiast przekierowywać przeglądarkę do innej lokalizacji, nakazujemy jej wysłanie kolejnego żądania, tyle że tym razem już bez zatwierdzania formularza. Ponieważ przeglądarkę trzeba skierować do kontrolera index.php przez wskazanie adresu URL katalogu nadrzędnego, wystarczy po prostu nakazać przeglądarce, by przeładowała katalog bieżący. Katalog bieżący wskazuje się za pomocą znaku kropki (.). 4
HTTP — skrót od HyperText Transfer Protocol — jest to język opisujący komunikację w formie żadanie-odpowiedź, wymienianą między przeglądarką użytkownika a serwerem WWW.
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
131
Dlatego dwa wiersze, które po dodaniu nowego kawału do bazy danych przekierowują przeglądarkę z powrotem do kontrolera, mają następującą treść. Listing 4.18. addjoke/index.php (fragment)
}
header('Location: .'); exit();
$_SERVER['PHP_SELF'] to adres URL bieżącej strony Kolejny powszechnie stosowany mechanizm odczytywania adresu URL bieżącej strony w języku PHP to użycie elementu $_SERVER['PHP_SELF']. Podobnie jak $_GET, $_POST i $_REQUEST, zmienna $_SERVER to zmienna tablicowa tworzona automatycznie przez język PHP. Tablica $_SERVER zawiera dość obszerny zbiór informacji przekazywanych przez serwer WWW. Element $_SERVER['PHP_SELF'] zawsze będzie zawierać adres URL bieżącego skryptu PHP, na podstawie którego serwer WWW wygenerował bieżącą stronę. Niestety, ponieważ serwer WWW automatycznie tłumaczy żądanie w postaci http:// localhost/addjoke/ do postaci http://localhost/addjoke/index.php, $_SERVER ´['PHP_SELF'] będzie zawierać ten drugi adres URL. Przekierowanie przeglądarki do lokalizacji wskazanej jako . pozwala zachować krótszą i prostszą do zapamiętania postać adresu URL. Z tego powodu unikam używania elementu $_SERVER['PHP_SELF'] w tej książce. Ponieważ jednak jest on często wykorzystywany w przykładowych skryptach PHP dostępnych w Internecie, pomyślałem, że warto o nim wspomnieć.
Pozostała część kodu kontrolera odpowiada, tak jak poprzednio, za wyświetlenie listy kawałów. Oto pełen kod źródłowy kontrolera. Listing 4.19. addjoke/jokes.php
Gdy będziesz jeszcze raz przeglądał kod i upewniał się, że jest w całości zrozumiały, pamiętaj, iż funkcje mysqli_connect i mysqli_select_db trzeba wywołać, zanim wykonany zostanie jakikolwiek kod, który wykonuje zapytania na bazie danych. Jednak do wyświetlenia formularza „Dodawanie kawału” połączenie z bazą danych nie jest niepotrzebne, dlatego wspomniany kod można umieścić na samym początku skryptu kontrolera. Warto gwoli testu załadować tę stronę do swojej przeglądarki i spróbować dodać do bazy kawał lub dwa. Strona, która powinna się pojawić po dodaniu dowcipu, została pokazana na rysunku 4.10. Rysunek 4.10. Patrz mamciu! Żadnego SQL-a!
I o to chodzi! Za pomocą pojedynczego kontrolera (index.php) możemy do naszej bazy MySQL dodawać nowe kawały i oglądać te, które już się tam znajdują.
Usuwanie danych z bazy W tym podrozdziale wprowadzimy jeszcze jedno, ostatnie rozszerzenie do witryny obsługującej bazę danych kawałów. Obok każdego dowcipu wyświetlonego na stronie umieszczony zostanie przycisk o nazwie Usuń, którego kliknięcie będzie powodować usunięcie kawału z bazy danych i wyświetlenie uaktualnionej listy dowcipów. Jeżeli lubisz wyzwania, możesz pokusić się o zaimplementowanie odpowiedniego mechanizmu samodzielnie, zanim przeczytasz opis mojego rozwiązania. Zadanie polega wprawdzie na zaimplementowaniu zupełnie nowego mechanizmu, lecz można do tego celu użyć w większości tych samych narzędzi, które były już wykorzystywane we wcześniejszych przykładach. Oto kilka podpowiedzi.
134
PHP i MySQL. Witryna WWW oparta na bazie danych Można to nadal bez problemu zrobić w ramach jednego skryptu kontrolera
(index.php). Konieczne będzie skorzystanie z instrukcji DELETE języka SQL, która została
opisana w rozdziale 2., „Wprowadzenie do systemu MySQL”. Aby usunąć ten kawał, a nie inny, konieczne będzie jednoznaczne zidentyfikowanie go. Kolumna identyfikatora id w tabeli kawal służy właśnie
do tego celu. Aby usunąć dowcip, należy wraz z żądaniem usunięcia kawału przesłać również jego identyfikator. Znakomitym miejscem na umieszczenie tej wartości jest ukryte pole formularza. Jeżeli nie czujesz się na siłach, by samodzielnie wykonać zadanie, pomyśl chociaż przez chwilę, jakbyś się do niego zabrał. Gdy już obmyślisz sposób działania i będzie gotów do poznania rozwiązania, przejdź do dalszej lektury. Na początek trzeba zmodyfikować zapytanie SELECT, które odczytuje listę kawałów z bazy danych. Oprócz kolumny tekstkawalu trzeba również pobierać kolumnę id, aby unikatowo zidentyfikować każdy dowcip. Listing 4.20. deletejoke/index.php (fragment) $result = mysqli_query($link, 'SELECT id, tekstkawalu FROM kawal'); if (!$result) { $error = 'Błąd odczytu kawału: ' . mysqli_error($link); include 'error.html.php'; exit(); }
Należy także zmodyfikować pętlę while, która zapisuje dane odczytane z bazy w tablicy $jokes. Zamiast po prostu umieszczać treść każdego kawału jako oddzielny element w tablicy, trzeba tym razem umieszczać zarówno identyfikator kawału, jak i jego treść. Można tego dokonać, powodując, by każdy element umieszczany w tablicy $jokes sam miał postać tablicy. Listing 4.21. deletejoke/index.php (fragment) while ($row = mysqli_fetch_array($result)) { $jokes[] = array('id' => $row['id'], 'text' => $row['tekstkawalu']); }
Po zakończeniu działania pętli będziemy mieli już przygotowaną tablicę $jokes, której każdy element będzie miał postać tablicy asocjacyjnej z dwoma elementami: identyfikatorem id kawału oraz jego treścią. Dla każdego kawału ($jokes[n]) można odczytać identyfikator id ($jokes[n]['id']) oraz treść ($jokes[n]['text']). W kolejnym kroku trzeba zmienić szablon jokes.html.php w taki sposób, aby odczytywał treść kawału z tablicy o nowej strukturze. Do każdego kawału trzeba również dodać przycisk Usuń.
Rozdział 4. ♦ Publikowanie w sieci WWW danych przechowywanych w bazie MySQL
135
Listing 4.22. deletejoke/jokes.html.php (fragment)
Można także odpowiednio zmienić kod szablonu, aby dla każdego kawału wyświetlane było również nazwisko jego autora. Listing 5.5. jokes/jokes.html.php (fragment)