Bazy danych w PHP PHPMyAdmin PHPMyAdmin jest aplikacją internetową służącą do łatwej obsługi bazy danych MySQL. Po zalogowaniu się do aplikacji w lewej części panelu wylistowane są wszystkie bazy danych. Aby utworzyć nową bazę, w prawej części panelu w polu "Utwórz bazę danych" wpisuje się nazwę bazy i wybiera metodę porównywania napisów, standardem jest utf8_general_ci. Tabelę tworzy się po wybraniu bazy wpisując jej nazwę w polu "Utwórz tabelę", oraz liczbę kolumn w polu "Liczba kolumn". W zależności od podanej wartości w polu "Liczba kolumn" zostaną wyświetlone pola opisujące jedną kolumnę: Nazwa - nazwa kolumny; Typ - typ kolumny - najczęściej stosowane typy to: INT - liczba całkowita; DECIMAL - liczba zmiennoprzecinkowa; VARCHAR - ciąg znaków (0..255); BLOB - przechowuje duże ilości danych binarnych; DATE - data; TIME - godzina; DATETIME - data i godzina; Długość/Wartości - maksymalna ilość znaków, w przypadku pól znakowych; Indeks - dla każdej tabeli powinno się stworzyć indeks główny (PRIMARY), który z reguły ustawia się dla pierwszego pola "id"; A_I - dodatkowy parametr dla indeksu głównego, oznaczający automatyczną inkrementację wartości tego pola. W aplikacji możliwy jest podgląd struktury tabeli oraz wykonania różnych operacji na aktualnie wybranej tabeli: Przeglądaj - wyświetla listę wierszy tabeli; Struktura - wyświetla listę wszystkich pól tabeli wraz z ich typem; SQL - umożliwia wysłanie do bazy MySQl własnego zapytania; Szukaj - umożliwia szukanie w zawartości tabeli; Wstaw - dodaje nowe wiersze do tabeli; Eksport - eksportuje tabelę; Import - importuje tabelę; Operacje - umożliwia wykonywanie różnych operacji tj.: zmiana nazwy, usuwanie tabeli;
Podstawy języka SQL Dodanie pojedynczego wiersza do tabeli: INSERT INTO tab_name (field_name1, fie_name2, ) VALUES (val1, val2, ); Wartości, które nie są liczbą podaje się w cudzysłowie bądź obejmuje apostrofami: INSERT INTO user (id, name, date) VALUES (122, "Zigi", "2010-12-06"); Do pobierania wierszy używa się kwerendy SELECT: SELECT field_name1, field_name1,... FROM table_name; Aby pobrać wszystkie wiersze z tabeli user: SELECT * FROM user; Aby pobrać tylko wybrane pola to zamiast gwiazdki podaje się nazwę tych pól: SELECT name, date FROM user; A pobrać konkretny wiersz wtedy konieczne jest zastosowanie dodatkowego warunku: SELECT * FROM user WHERE id=122; Powyższe zapytanie pobierze wiersz, którego id jest równe 122. Można stosować także inne znaki logiczne, podobnie jak w języku PHP: <, <=, >, >=,!=. W klauzuli WHERE można stosować słowo kluczowe LIKE: SELECT id FROM user WHERE name LIKE "Z%"; Znak % zastępuje dowolną ilość znaków. Powyższe zapytanie zwróci wszystkie wiersze, dla których wartość pola name zawiera ciąg znaków rozpoczynający się od znaku "Z". W jednym zapytaniu może występować kilka warunków połączonych za pomocą sumy logicznej (OR) lub iloczynu logicznego (AND): SELECT * FROM user WHERE id>3 AND id<30; Powyższe zapytanie pobierze wszystkie wiersze, których wartość pola id jest większa od 3 i mniejsza od 30. Wynik zapytania można ograniczyć za pomocą słowa kluczowego LIMIT: SELECT * FROM user LIMIT 0, 10; Powyższe zapytanie pobierze 10 wierszy z wyniku poczynając od pierwszego wiersza (0). Aby pobrać kolejne 10 wystarczy wykonać poniższe zapytanie: SELECT * FROM user LIMIT 1,10; Aby posortować wynik należy użyć słowa kluczowego ORDER BY: SELECT * FROM user ORDER BY name;
Aby posortować wynik w odwrotnym kierunku wystarczy dodać słowo kluczowe DESC: SELECT * FROM user ORDER BY name DESC; Można także sortować względem większej ilości pól np: SELECT * FROM user ORDER BY name DESC, first_name DESC; Poniżej przykład zapytania SELECT z wykorzystaniem wszystkich słów kluczowych, które zostały przedstawione: SELECT * FROM user WHERE id>0 AND (imie="jan" OR imie="janka") AND nazwisko LIKE "N%" ORDER BY name, first_name LIMIT 0,10; Przykład obrazuje w jakiej kolejności należy używać poszczególnych słów kluczowych w zapytaniu. Często zachodzi konieczność łączenia kilku tabel. Jeśli np.: mamy tabelę user, która zawiera listę użytkowników, mieszkających w określonym mieście. Taka tabela mogłaby wyglądać następująco: [user] id INT first_name VARCHAR(20) name VARCHAR(32) city VARCHAR(32) Można zauważyć, że takie rozwiązanie nie jest optymalne, ponieważ miasta w tabeli user będą się powtarzać. W tym przypadku można utworzyć dodatkową tabele słownikową, która zawierałaby wyłącznie listę miast wraz z przyporządkowanym im identyfikatorem: [city] id nazwa W takim przypadku tabela z listą użytkowników wyglądałaby następująco: [user] id INT first_name VARCHAR(20) name VARCHAR(32) city_id Aby pobrać imię, nazwisko i nazwę miasta, w którym mieszka dany użytkownik należy połączyć obie tabele: SELECT first_name, name, c.name AS city FROM user AS u INNER JOIN city AS c ON u.city_id=c.id Powyższe zapytanie do każdego wiersza z tabeli user dołączy wiersz z tabeli city, którego wartość pola id jest równa wartości pola city_id z tabeli user. Słowo kluczowe AS służy do utworzenia aliansu w bieżącym zapytaniu. Dzięki czemu tabela user jest reprezentowana jako "u", a tabela city jako "c". Aby odnieść się do pola z tabeli city wystarczy wpisać c.name zamiast city.name.
Aby zmienić wartości w tabeli wystarczy użyć zapytania typu UPDATE: UPDATE user SET first_name="stefan", name="kowalski"; Powyższe zapytanie zmieni wartości pól first_name i name we wszystkich wierszach tabeli user. Aby zmienić tylko wybrane wiersze należy użyć znanej już klauzuli WHERE: UPDATE user SET first_name="stefan", name="kowalski" WHERE first_name="jan"; Aby usunąć wiersze z tabeli używa się zapytania DELETE: DELETE FROM user; Powyższe zapytanie usunie wszystkie wiersze z tabeli. Aby usunąć wybrane wiersze należy zastosować klauzule WHERE: DELETE FROM user WHERE id=122; PHP Data Objects PHP Data Objects (PDO) jest biblioteką udostępniającą jednolity interfejs dostępu do wielu popularnych baz danych (MSSQL, Firebird, MySQL, Informix, Oracle, ODBC, DB2, SQLite, PostgreSQL), domyślnie dostępną od PHP 5.1. W stosunku do poprzednich funkcji PHP umożliwiających dostęp do baz danych PDO oferuje dodatkowo bindowanie parametrów, zwracanie całej tablicy oraz obsługę wyjątków. Aby połączyć się z baza MySQL w konstruktorze klasy PDO należy podać odpowiedni ciąg znaków DSN (Data Source Name), który określi sterownik bazy, jej nazwę, oraz nazwę hosta wraz z portem. Drugi i trzeci parametr określa nazwę użytkownika i hasło. Ostatni parametr jest opcjonalny i pozwala ustawić dodatkowe opcje specyficzne dla danego sterownika. Można przykładowo ustawić kodowanie UTF-8 dla połączenia z bazą danych. Jeśli podczas próby podłączenia do bazy danych wystąpi jakikolwiek problem to zostanie wyrzucony wyjątek, który należy przechwycić i obsłużyć w odpowiedni sposób. Z bazą danych łączy się tylko raz, następnie korzysta się z utworzonego obiektu PDO we wszystkich skryptach. try { $db = new PDO('mysql:host=localhost;dbname=database;port=3306', 'root', 'pass', array(pdo::mysql_attr_init_command => "SET NAMES utf8")); catch (PDOException $e) { echo 'Błąd: '.$e->getmessage(); Zapytania do bazy wykonuje się przy pomocy trzech następujących metod: PDO::query()- metoda używana do pobierania danych z bazy (np. z zapytaniem SELECT), wynikiem metody jest obiekt klasy PDOStatement; PDO::exec()- metoda używana do wysyłania zapytań, które nie zwracają żadnego rezultatu, wynikiem tej metody jest liczba zmodyfikowanych bądź usuniętych wierszy (używana z zapytaniami INSERT, UPDATE, DELETE); PDO::prepare()- metoda używana i zalecana do zapytań, które wymagają dołączenia dodatkowych wartości (bindowania), wynikiem tej metody jest obiekt klasy PDOStatement.
Klasa PDOStatement implementuje interfejs pozwalający na iterację wyników oraz posiada metody służące do pobierania danych z wyniku zapytania tj: PDOStatement::fetch()- pobiera jeden wiersz w postaci tablicy połączonej z tablicą asocjacyjną. W przypadku niepowodzenia metoda zwraca FALSE. Aby pobrać dane w postaci tablicy asocjacyjnej należy podać w parametrze stałą wartość PDO::FETCH_ASSOC. Metoda użyta ponownie zwraca kolejny wiersz. PDOStatement::fetchAll() - metoda analogiczna do metody PDOStatement::fetch() z tą różnicą, że pobierane są wszystkie wiersze. Wynikiem jest tablica dwuwymiarowa, bądź pusta tablica w przypadku braku wyników. PDOStatement::fetchColumn()- metoda zwraca jedną wartość z wybranej kolumny. Domyślną kolumną jest pierwsza kolumna (indeks 0), którą można zmienić podając w parametrze metody liczbę określającą indeks kolumny. W przypadku braku wyników zostanie zwrócony pusty string. Kolejne użycie tej metody powoduje pobranie wartości z kolejnego wiersza wybranej kolumny. Przykłady pobrania danych z bazy: $db = new PDO($dsn, $user, $password); $stmt = $db->query('select first_name, last_name FROM user'); // Sposób 1 foreach ($stmt as $row) { echo $row['first_name'].' '.$row['last_name']; // Sposób 2 while ($row = $stmt->fetch()) { echo $row['first_name'].' '.$row['last_name']; // Sposób 3 foreach ($stmt->fetchall() as $row) { echo $row['first_name'].' '.$row['last_name']; // Pobierana jest tylko wartość z drugiej kolumny pierwszego wiersza echo $stmt->fetchcolumn(1); Przy pobieraniu dużej ilości danych powinno się używać sposobu drugiego ponieważ metoda PDOStatement::fetchAll() tworzy tablicę, której rozmiar może przekroczyć dopuszczalną wartość. Dużą ilość danych powinno się odpowiednio porcjować. W przypadku pobierania tylko jednego wiersza stosuję się metodę PDOStatement::fetch(), która zwraca tablicę jednowymiarową: $stmt = $db->query('select * FROM user WHERE id=31'); $row = $stmt->fetch(pdo::fetch_assoc); Metoda PDOStatement::fetchColumn() służy do pobrania liczby wierszy w tabeli: $stmt = $db->query('select COUNT(*) FROM user WHERE status=2'); $count = $stmt->fetchcolumn();
Aby wykonać zapytanie do bazy, które nie zwraca danych, używa się metody PDO::exec(): $db->exec('delete FROM user WHERE status=3'); Jeśli w zapytaniu dołączane są dodatkowe zmienne używa się metody PDO::prepare(). Wtedy w zapytaniu zamiast zmiennych podaje się odpowiedni ciąg znaków (przykładowo alias dla zmiennej bądź stałej): $stmt = $db->prepare('select * FROM user WHERE status=:status AND last_logged<:date'); Parametry bindowane są w następujący sposób: $stmt->bindvalue(':status', User::STATUS_DELETE, PDO::PARAM_INT); $stmt->bindvalue(':date', $date, PDO::PARAM_STR); Podany alias w zapytaniu zostanie zamieniony na wartość przy pomocy metody bindvalue() (drugi parametr metody). Ostatni parametr metody określa typ zamienionej wartości, najczęściej są to stałe PDO::PARAM_INT dla wartości liczbowych oraz PDO::PARANM_STR dla ciągu znaków. Tak przygotowane zapytanie jest zabezpieczone przed atakiem SQL Injection. Następnie zapytanie wysyłane jest do bazy danych za pomocą metody PDOStatement::execute(), która zwraca wartość logiczną. $stmt->execute(); W przypadku zapytań: INSERT, UPDATE, DELETE cały proces kończy się w tym miejscu. W przypadku zapytania SELECT, aby pobrać dane należy użyć następujących metod klasy PDOStatement: $rows = $stmt->fetchall(pdo::fetch_assoc); Metoda PDO::prepare() umożliwia ponowne użycie przygotowanego zapytania na innym zestawie danych. $stmt = $db->prepare('insert INTO user (first_name, last_name, status) VALUES(:first_name, :last_name, 1)'); $count = 0; foreach ($users as $user) { $stmt->bindvalue(':first_name', $user->firstname, PDO::PARAM_STR); $stmt->bindvalue(':last_name', $user->lastname, PDO::PARAM_STR); $count += $stmt->execute(); if (count($users)!= $count) { throw new Exception('Wystąpił błąd podczas dodawania rekordów.'); Należy pamiętać aby po każdym zapytaniu na utworzonym obiekcie klasy PDOStatement wywołać metodę PDOStatement::closeCursor(). Nie wywołanie tej metody może powodować błędy przy wysyłaniu kolejnych zapytań.
W przypadku gdy potrzebne jest wykonanie minimum dwóch zapytań, które dodają, modyfikują bądź usuwają rekordy z bazy i są ze sobą powiązane używa się transakcji. W celu ułatwienia pracy ustawia się specjalny atrybut PDO, który wszystkie błędy będzie wyrzucał w postaci wyjątków: $db->setattribute(pdo::attr_errmode, PDO::ERRMODE_EXCEPTION); Następnie kod odpowiedzialny za dodawanie, modyfikowanie bądź usuwanie rekordów obejmuje się klauzulą try. Poniżej przykład zastosowania transakcji: $db = new PDO($dsn, $user, $password); $db->setattribute(pdo::attr_errmode, PDO::ERRMODE_EXCEPTION); try { $db->begintransaction(); // rozpoczecie transakcji $stmt = $db->prepeare('delete FROM user WHERE id=:id'); $stmt->bindvalue(':id', $id, PDO::PARAM_INT); $stmt->execute(); $stmt->closecursor(); // Zamknięcie kursora $stmt = null; // Wyzerowanie - tak dla pewności $stmt = $db->prepeare('delete FROM book WHERE user_id=:id'); $stmt->bindvalue(':id', $id, PDO::PARAM_INT); $stmt->execute(); $stmt->closecursor(); // Zamknięcie kursora $db->commit(); // Wykonanie transakcji catch (PDOException $e) { $db->rollback(); // Cofnięcie zmian z powodu błedu echo $e->getmessage(); Obsługa wyjątków jest uproszczona ponieważ klasa PDOException dziedziczy po Exception, dlatego każdy wyjątek w klauzuli try, zostanie przechwycony (łącznie z wyjątkami PDO) i zmiany na bazie zostaną cofnięte.