mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 5. Współpraca z bazą danych MySQL 5.1. Informacje ogólne Język PHP posiada obsługę wielu relacyjnych baz danych, jedną z najpopularniejszych jest baza MySQL. PHP pozwala na pełną współpracę z bazą. Praca polega na otwarciu sesji, zadaniu zapytania, lub zapytań, odebraniu ewentualnych wyników i na koniec zamknięciu sesji. Obsługa MySQL jest zewnętrznym modułem i trzeba ją włączyć przy kompilacji PHP (zwłaszcza PHP 5). Rzecz jasna PHP obsługuje zarówno połączenia z lokalną bazą danych (znajdującą się na tym samym serwerze co wykonywany skrypt), jak i z bazami zdalnymi, za pomocą protokołu TCP/IP. 5.2. Nawiązanie połączenia – mysql_connect() Za pomocą tej funkcji tworzymy nowe połączenie z bazą danych: $polaczenie = mysql_connect(host[:port], uzytkownik, haslo); Wszystkie parametry funkcji są opcjonalne. Pierwszy parametr to nazwa, lub adres IP serwera na którym znajduje się baza. Domyślną nazwą jest „localhost”, domyślnym portem 3306. Następnie mamy nazwę użytkownika bazy, wartością domyślną jest nazwa użytkownika procesu wykonującego skrypt (najczęściej będzie to „httpd”), po nim hasło tego użytkownika, wartością domyślną jest pusty łańcuch tekstowy. Wynikiem funkcji jest wartość typu zasób identyfikująca połączenie (to ważne, jeżeli w skrypcie mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. wykonujemy więcej niż jedno połączenie). W przypadku niepowodzenia zwracana jest wartość logiczna FALSE. 5.3. Użycie operatora die i operatora @ przy obsłudze błędów Przy łączeniu się z bazą danych stosunkowo często zdarzają się niepowodzenia. Błędy takie wymagają prawidłowej obsługi, w przeciwnym wypadku dostarczamy potencjalnym hakerom przydatnich informacji. Oto prosty przykład: $c = mysql_connect('jakis.serwer.com.pl:9384', 'httpd', 'tajne_haslo'); W przypadku niepowodzenia połączenia, użytkownik w przeglądarce zobaczy taki oto tekst: Warning: mysql_connect(): Unknown MySQL Server Host 'jakis.serwer.com.pl' (0) in / home/krashan/public_html/t.php on line 9 Albo na przykład coś takiego (dla innego serwera): Warning: mysql_connect(): Access denied for user: 'httpd@localhost' (Using password: YES) in /home/krashan/public_html/t.php on line 9 Na szczęście hasło nie jest podawane, ale sporo informacji wycieka (np. lokalizacja skryptu, serwer na którym jest baza, nazwa użytkownika). Nie powinniśmy dopuścić do mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. pokazania takich informacji użytkownikowi. Do ich zablokowania użyjemy operatorów die i @. Drugi z nich, jak wiadomo, blokuje wypisywanie wiadomości o błędach, jednak jakąś wiadomość dobrze by było wyświetlić, żeby użytkownik mniej więcej wiedział gdzie jest problem. Tui możemy posłużyć się operatorem die, który po wypisaniu wskazanej wiadomości powoduje natychmiastowe zakończenie skryptu. Oto przykładowe zastosowanie: $c = @mysql_connect('jakis.serwer.com.pl:9384', 'httpd', 'tajne_haslo') or die "Problem z połączeniem z bazą danych!"; Tym razem jedyne, co użytkownik zobaczy na ekranie w przypadku nienawiązania połączenia, będzie napis: Problem z połączeniem z bazą danych! Nie ujawniamy więc żadnych informacji potencjalnym włamywaczom. Kilka słów wyjaśnienia na temat zastosowanego operatora or. W przypadku dwóch wyrażeń połączonych tym operatorem, PHP najpierw ewaluuje (a więc wykonuje) najpierw pierwsze z nich, w tym przypadku łączy się z bazą danych. Jeżeli wynik tego wyrażenia konwertuje się do logicznej prawdy, drugie wyrażenie nie jest wykonywane (bo TRUE or cokolwiek = TRUE). Jeżeli zaś pierwsze wyrażenie ma wartość FALSE, to wykonywane jest drugie, bo jego wartość jest niezbędna do ustalenia wartości całego wyrażenia. Zatem die() wykona się tylko jeśli mysql_connect() zwróci FALSE. mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 5.4. Zamykanie połączenia z bazą – mysql_close() Tutaj mamy sytuację podobną jak przy plikach. W zasadzie nie jesteśmy zobligowani do zamykania sesji MySQL, ponieważ zostają one zamknięte automatycznie przy wyjściu ze skryptu. Niemniej jednak wskazane jest (ze względu na oszczędne gospodarowanie zasobami) zamykanie połączenia, gdy nie jest ono już potrzebne. Oto przykład zamknięcia połączenia: mysql_close($polaczenie); Gdzie $polaczenie to oczywiście identyfikator zwrócony przez mysql_connect(). Można też wywołać tę funkcję bez parametru, wtedy zamykane jest ostatnio otwarte połączenie. Jest to wygodne, gdy w skrypcie jest tworzone tylko jedno połączenie. 5.5. Wybór bazy danych – mysql_select_db() Tak jak i przy pracy z klientem MySQL, pierwszym krokiem przy pracy jest wybór bazy na której będziemy pracować: mysql_select_db('nazwa'); Oczywiście użytkownik, którego podaliśmy przy nawiązywaniu połączenia, musi mieć dostęp do wybranej bazy. Ewentualne błędy z tym związane uwidocznią się dopiero przy wysłaniu zapytania, jako że mysql_select_db() nie zwraca żadnej wartości. mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 5.6. Wysyłanie zapytań – mysql_query() Funkcja ta służy do wysyłania wszelkiego rodzaju zapytan do bazy, zarówno tych odczytujących informacje, jak i tych modyfikujących. Dozwolony jest cały repertuar języka SQL (PHP nie sprawdza zapytania pod względem składniowym ani merytorycznym). Wynik funkcji zależy od rodzaju zapytania. W przypadku zapytań zwracających informację (przede wszystkim SELECT, a także SHOW, DESCRIBE i EXPLAIN), wynikiem jest zmienna typu zasób używana później do pobierania informacji ze zwróconej odpowiedzi. Dla zapytań modyfikujących, takich jak UPDATE, DROP czy DELETE zwracana jest wartość logiczna TRUE. W przypadku niepowodzenia, dla wszystkich zapytań zwracane jest logiczne FALSE. Przykład użycia: if ($odp = mysql_query('SELECT * FROM tablica WHERE id = 46')) { // rób coś z odpowiedzią mysql_free_result($odp); } Przyczyną wielu błędów przy tej funkcji jest niepoprawne ustawienie praw użytkowników w bazie danych, oczywiście użytkownik podany przy otwieraniu połączenia musi mieć uprawnienia do zadawania używanych w mysql_query() typów zapytań. mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 5.7. Zwalnianie wyników zapytania – mysql_free_result() Zapytania kierowane do bazy danych często zwracają sporą ilość informacji. Wykonując funkcję mysql_query() PHP rezerwuje pamięć na wszystkie podawane przez bazę danych informacje. Mająz na względzie oszczędne gospodarowanie zasobami serwera (przede wszystkim wolną pamięcią) powinno się zwalniać odpowiedź na zapytanie w chwili, gdy nie jest już potrzebna. Jeżeli tego nie zrobimy, zrobi to za nas PHP, ale dopiero przy wyjściu ze skryptu. Jedynym parametrem mysql_free_result() jest zasób zwrócony uprzednio przez mysql_query(). Jeżeli nie podamy tego parametru zostanie zwolniony wynik ostatniego zapytania (zwracającego dane). Przykład użycia tej funkcji znajduje się w rozdziale 5.6. 5.8. Ogólne informacje o wykonanym zapytaniu Funkcja mysql_num_rows() zwraca ilość wierszy danych znajdujących się w odpowiedzi na zapytanie SELECT, SHOW, czy DESCRIBE. Parametrem tej funkcji jest identyfikator odpowiedzi zwrócony przez mysql_query(). Funkcja mysql_affected_rows() podaje ilość wierszy tablicy w bazie danych zmodyfikowanych przez zapytania takie jak UPDATE, DELETE, czy DROP. mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 5.9. Sposoby pobierania informacji z zapytania Wynik zapytania zwrócony przez mysql_query(), jest zwykle tablicą złożoną z wybranych przez zapytanie danych. Nie jest on jednak tablicą z punktu widzenia PHP, wszak rezultat zapytania jest typu zasób. PHP pozwala na sięganie do odpowiedzi z bazy całymi wierszami, bądź też dostęp do pojedynczych pól. 5.9.1. mysql_fetch_row() To najczęściej używana funkcja czytająca jeden wiersz odpowiedzi. Z wiersza tego tworzona jest tablica, której kolejne elementy o kluczach 0, 1, 2... zawierają wartości z kolejnych kolumn tableli SQL wybranych zapytaniem. Załóżmy, że mamy następującą tabelę w MySQL: imie nazwisko wiek varchar(20) varchar(30) smallint(3) Wyślijmy teraz zapytanie: $w = mysql_query('SELECT * FROM tabela'); mysql_fetch_row() zwróci nam taką tablicę: mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 0 => [imie] 1 => [nazwisko] 2 => [wiek] Teraz inne nieco zapytanie: $w = mysql_query('SELECT wiek, imie FROM tabela'); Tablica zwracana przez mysql_fetch_row() wygląda teraz inaczej: 0 => [wiek] 1 => [imie] Po zwróceniu aktualnego wiersza odpowiedzi, następuje przejście do następnego. Jeżeli więc będziemy wywoływać mysql_fetch_row() w pętli, to dostaniemy tablice zawierające kolejne wiersze tabeli zwróconej przez zapytanie. W momencie dotarcia do końca tabeli, funkcja zwróci FALSE. 5.9.2. mysql_fetch_assoc() Funkcja podobna do poprzedniej, z tym, że kluczami zwracanej tablicy są nazwy kolumn z SQL-a (ewentualnie zmienione w zapytaniu). Przy założeniu, że operujemy na tabeli SQL jak w punkcie 5.9.1, poniższe zapytania dadzą odpowiedzi jak pokazano: mysql_query('SELECT * FROM tabela'); mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 'imie' => [imie] 'nazwisko' => [nazwisko] 'wiek' => [wiek] Przykład zapytania ze zmianą nazw kolumn: $w = mysql_query('SELECT wiek AS latka, imie AS cokolwiek FROM tabela'); Tablica zwracana przez mysql_fetch_assoc() wygląda w tym przypadku tak: 'latka' => [wiek] 'cokolwiek' => [imie] Tak samo jak dla mysql_fetch_row(), po zwróceniu aktualnego wiersza odpowiedzi, następuje przejście do następnego. 5.9.3. mysql_result() Ta z kolei funkcja pozwala na dostęp do pojedynczego pola tabeli zwróconej w odpowiedzi na zapytanie. Generalnie jest ona wolniejsza od poprzednich, więc jeżeli przetwarzamy całe wiersze danych, nie jest zalecana. Zawsze lepiej jest ograniczyć zakres danych w zapytaniu do bazy, niż w samym skrypcie PHP. Dzięki temu mniej danych jest przesyłanych z bazy do skryptu, zmniejszamy też zużycie pamięci. Ograniczenie zakresu danych w skrypcie jest usprawiedliwione tylko wtedy, gdy kryterium jest na tyle skomplikowane, że trudno je zapisać w zapytaniu SQL. mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. Funkcja mysql_result() przyjmuje trzy parametry. Pierwszy to identyfikator odpowiedzi na zapytanie, zwrócony przez mysql_query(). Drugi to numer wiersza, a trzeci, opcjonalny to numer, albo nazwa kolumny (domyślnie pierwsza kolumna). Funkcja działa szybciej, jeżeli podamy numer kolumny zamiast nazwy. Oto przykład pokazujący niewłaściwe użycie mysql_result() i prawidłowy sposób ograniczenia zakresu danych w samym zapytaniu. Poszukujemy w tabeli opisanej w punkcie 5.9.1 nazwisk wszystkich osób o imieniu Jan i wieku poniżej 40 lat: $q = mysql_query('SELECT * FROM tabela') or die ('Błąd!'); for ($i = 0; $i < mysql_num_rows($q); $i++) { if ((mysql_result($q, $i, 'imie') == 'Jan') and (mysql_result($q, $i, 'wiek') < 40)) { echo(mysql_result($q, $i, 'nazwisko')); echo('<br>'); } } A teraz tak, jak to powinno być zrobione: $q = mysql_query("SELECT nazwisko FROM tabela WHERE imie=\"Jan\" AND wiek<40") or die ('Błąd!'); while ($wiersz = mysql_fetch_row($q)) print("{$wiersz[0]}<br>"); mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. 5.10. Pomijanie danych – mysql_data_seek() Jedyną do tej pory poznaną funkcją pozwalającą na przeskakiwanie nieinteresujących danych, była nienajszybsza mysql_result(). Przy pracy całymi wierszami na swobodne przesuwanie się po wierszach tabeli pozwala mysql_data_seek(). Oto sposób użycia: mysql_data_seek($wynik, $wiersz); Wskaźnik danych w wyniku identyfikowanym przez $wynik zostaje przesunięty do wiersza o numerze $wiersz. Jeżeli podany wiersz nie istnieje, funkcja zwróci FALSE. Następne wywołanie mysql_fetch_row() lub mysql_fetch_assoc() załaduje podany wiersz. Jeszcze raz podkreślam, że zdecydowanie lepiej jest odrzucić niepotrzebne wiersze już na poziomie zapytania do bazy danych (poprzez odpowiednie użycie słowa kluczowego WHERE), niż ładować dużą tabelę i obrabiać ją w PHP. 5.11. Długości poszczególnych pól – mysql_fetch_lenghts() Funkcja ta służy do pobrania długości (w znakach) pól ostatnio załadowanego (przy pomocy mysql_fetch_row() lub mysql_fetch_assoc()) wiersza. Zwracana jest tablica z kluczami numerycznymi, wartości odpowiadają długościom pól tabeli. Oto przykład, jeżeli zwrócony przez mysql_fetch_assoc() wiersz wygląda tak: 'imie' => 'Władysław', 'nazwisko' => 'Gomułka', 'wiek' => 107 mgr inż. Grzegorz Kraszewski – TECHNOLOGIE INTERNETOWE 3 – wykład 5: „Współpraca z MySQL”. to tablica zwrócona przez mysql_fetch_lenghts() będzie miała następującą postać: 0 => 9, 1 => 7, 2 => 3