C
M
Y
K
SQLite
SQLite posiada sporo cech, które odró¿niaj¹ to rozwi¹zanie od typo-
wych baz danych. Niektórzy lubi¹ j¹ okreœlaæ jako plikow¹ bazê da-
nych. Do przechowywania wszystkich danych wykorzystuje ona bo-
wiem pliki. Gdy tworzymy bazê danych w SQLite, tworzymy plik na
dysku serwera, który póŸniej otwieramy i wykonujemy na nim zapyta-
nia. To rozszerzenie PHP5 jest wiêc czymœ w rodzaju miniaturowej ba-
zy danych, która nie potrzebuje otwieraæ osobnych procesów, by mog³a
pracowaæ. Co wiêcej, w PHP5 baza SQLite dostêpna jest domyœlnie,
nie musimy wiêc niczego ju¿ instalowaæ. Instalujemy PHP5, a wraz
z nim dostajemy w pe³ni dzia³aj¹c¹ bazê danych. Za pomoc¹ rozszerze-
nia SQLite mo¿emy utworzyæ w dowolnej chwili now¹ bazê danych.
SQLite utworzy plik na dysku serwera, dok³adnie o takiej nazwie jak¹
sami ustalimy. Nastêpnie mo¿emy wykonaæ na tej bazie zapytania, np.
dodaæ nowe tabele do bazy wraz z danymi. SQLite jest niemal w 100%
zgodny z jêzykiem SQL92. Bez przeszkód wykonamy dowolne zapyta-
nia typu SELECT, UPDATE, INSERT, stworzymy w³asne funkcje
(piszemy je w PHP, a póŸniej wykorzystujemy podczas pracy z SQLi-
te), widoki, zapytania podrzêdne, prze³¹czniki, transakcje.
SQLite to baza opieraj¹ca siê o pliki tekstowe, ma wiêc kilka wad,
które charakteryzuj¹ tego typu rozwi¹zania:
!
nie mo¿na modyfikowaæ dotychczasowych struktur tabeli za
pomoc¹ sk³adni ALTER TABLE, choæ jest to problem mo¿liwy
do obejœcia,
!
brak jest mo¿liwoœci tworzenia obcych kluczy,
!
widoki pracuj¹ tylko w trybie do odczytu,
!
nie dzia³aj¹ polecenia RIGHT OUTER JOIN i FULL OUTER
JOIN,
!
nastêpuje blokowanie dostêpu do pliku bazy danych podczas
zapisu.
Baza SQLite jest przede wszystkim znakomitym substytutem
dla p³askich baz danych i jest w stanie wyprzeæ je w ca³oœci. P³a-
skie bazy danych to wszelkiego rodzaju pliki tekstowe, które maj¹
s³u¿yæ do nieskomplikowanego przechowywania danych. Kolejne
rekordy w takich bazach oddziela znak nowej linii, natomiast kolej-
ne rekordy oddziela siê wed³ug upodobania autora rozwi¹zania, np.
tabulatorem.
SQLite ma szanse odnieœæ sukces g³ównie dlatego, ¿e jest rozwi¹-
zaniem dostêpnym domyœlnie wraz z PHP5. Za jego szansami na suk-
ces przemawia wiele faktów:
!
prostota korzystania,
!
brak koniecznoœci instalacji i konfiguracji,
!
wydajnoœæ, szczególnie w transakcjach,
!
tymczasowe bazy tworzone w pamiêci serwera,
!
interfejs u¿ytkownika zbli¿ony do MySQL.
O SQLite Czytelnicy MI mieli ju¿ okazjê siê dowiedzieæ z artyku-
³ów opublikowanych w numerach 4 i 5/2004. W pierwszej czêœci zna-
laz³o siê szczegó³owe omówienie zastosowañ i mo¿liwoœci SQLite.
Druga czêœæ to praktyczna prezentacja mo¿liwoœci SQLite wraz
z przyk³adami realizacji poszczególnych zadañ. Dlatego te¿ w trzeciej
czêœci kursu wprowadzaj¹cego do PHP5 nakreœlone zostan¹ jedynie
podstawowe zagadnienia dotycz¹ce pracy z SQLite w sposób obiekto-
wy, poniewa¿ praca z SQLite w paradygmacie obiektowym jest do-
stêpna dopiero od PHP5. Artyku³ z maja prezentowa³ jedynie przyk³a-
dy w formie proceduralnej, dostêpne zarówno w PHP4, jak i w PHP5.
Interfejs obiektowy
W PHP5 ma dominowaæ interfejs obiektowy. Do jego obs³ugi zosta³
przystosowany równie¿ i interfejs bazy SQLite:
PHP
INTERNET.listopad.2004
100
NA CD
NEWSY
Z OK£ADKI
FIRMA
MAGAZYN
PROGRAMY
WARSZTAT
!
W ostatniej czêœci wprowadzenia do PHP5
skupimy siê na tematyce obs³ugi baz
danych w PHP5. Korzystanie z baz danych
w jêzykach skryptowych jest obecnie
tak oczywiste, ¿e nie sposób wyobraziæ
sobie strony, która nie wykorzystywa³aby
baz danych. Lecz o ile w PHP4 dominowa³
model LAMP – Linux Apache MySQL PHP,
o tyle w PHP5 mamy do czynienia z trendem
ku zmianom.
Pawe³ Grzesiak
PHP5
CO NOWEGO W
(cz. 3)
Bazy danych
UWAGA!
Poprzednie części tego cyklu
są na płycie CD!
Wszystkie przykłady opisane w artykule
znajdują się na dołączonej płycie CD
w katalogu Warsztat_PHP.
C
M
Y
K
<?
$sqlite = new SQLiteDatabase(”jakasbaza.sqlite”);
$sqlite->query(’CREATE TABLE jakastabela
!
(id INTEGER PRIMARY KEY, a, b);
INSERT INTO jakastabela (a,b) VALUES
!
(”abcd”, ”1.43”);’);
echo ’Ostatnio dodany ID: ’.$sqlite->
!
lastInsertRowid();
$array = $sqlite->arrayQuery(’SELECT * FROM
!
jakastabela WHERE id = 1’, SQLITE_ASSOC);
print_r($array);
?>
Nowy obiekt bazy danych SQLite tworzymy poprzez utworzenie
instancji klasy SQLiteDatabase, podaj¹c przy tym parametr w postaci
nazwy pliku bazy danych. Je¿eli plik ten nie istnieje, baza danych o ta-
kiej nazwie zostanie utworzona na dysku serwera. W przyk³adzie za
pomoc¹ metody query() tworzymy tabelê sk³adaj¹c¹ siê z trzech ko-
lumn. Pierwsza kolumna jest typu INTEGER PRIMARY KEY, co od-
powiada MySQLowemu typowi auto_increment. Pozosta³e kolumny
nie posiadaj¹ typu, poniewa¿ SQLite nie wymaga ich podawania. Dla
SQLite jest ca³kowicie obojêtnie jaki typ danych podamy, bowiem ta
baza ich nie u¿ywa. Posiada w³asne mechanizmy, które przy sortowa-
niu danych wykryj¹ jakiego typu danych jest kolumna i podejd¹ do
kwestii sortowania w sposób doœæ specyficzny (o czym by³a mowa
w artykule „SQLite cz. 2”, MI 5/2004). Poniewa¿ podczas jednego
wywo³ania metody query() mo¿na wykonaæ dowoln¹ iloœæ zapytañ,
oprócz utworzenia tabeli wprowadzamy do niej ponadto jeden przyk³a-
dowy rekord. Nastêpna linia przyk³adu, zawieraj¹ca wywo³anie meto-
dy lasInsertRowId(), zwróci identyfikator liczbowy ostatnio dodanego
wiersza. Kolejno skorzystamy z metody arrayQuery, która jest swoje-
go rodzaju kompilacj¹ metod query() i fetch_array(). Pierwszym para-
metrem przy wywo³ywaniu tej metody jest zapytanie, natomiast dru-
gim sposób odbioru danych (tu: tablica asocjacyjna). Wynikiem dzia-
³ania tej metody jest tablica asocjacyjna, któr¹ wyœwietlamy na ekranie
przy u¿yciu print_r.
Wynik realizacji powy¿szego przyk³adu jest nastêpuj¹cy:
Ostatnio dodany ID: 1
Array
(
[0] => Array
(
[id] => 1
[a] => abcd
[b] => 1.43
)
)
Praca z SQLite jest zbli¿ona do pracy z MySQL. Zmiany w nazew-
nictwie w interfejsie obiektowym spowodowa³y jednak niewielk¹ nie-
zgodnoœæ nazw w porównaniu z poprzednim stanem.
Bazy typu :memory:
Bardzo interesuj¹c¹ w³aœciwoœci¹ bazy danych SQLite jest mo¿liwoœæ
tworzenia baz danych, które zostan¹ ulokowane w pamiêci serwera. S¹
one szczególnie przydatne, gdy musimy dokonaæ obróbki jakichœ da-
nych, a nie chcemy do tego celu tworzyæ klasycznej bazy danych zapi-
sanej na dysku twardym serwera. Wówczas bazy typu :memory:
dostarcz¹ potrzebnych narzêdzi, jednoczeœnie nie stwarzaj¹c potrzeby
lokowania bazy na dysku serwera, lecz w jego ulotnej pamiêci. W pro-
sty sposób mo¿na utworzyæ bazê danych typu „:memory:”:
<?
$sqlite = new SQLiteDatabase(”:memory:”);
$sqlite->query(’CREATE TABLE jakastabela
!
(id INTEGER PRIMARY KEY, a, b);
INSERT INTO jakastabela (a,b) VALUES
!
(”abcd”, ”1.43”)’);
echo ’Ostatnio dodany ID: ’.$sqlite->lastInsertRowid();
$array = $sqlite->arrayQuery(’SELECT * FROM
!
jakastabela WHERE id = 1’, SQLITE_ASSOC);
print_r($array);
?>
Przyk³ad jest niemal identyczny jak poprzedni. Jedyn¹ ró¿nic¹ jest to, ¿e
SQLite tworzy bazê w pamiêci serwera, co zasygnalizowaliœmy bazie po-
przez wprowadzenie do konstruktora parametru „:memory:”. Wraz z zakoñ-
czeniem tego skryptu ca³a baza zostanie bezpowrotnie usuniêta z pamiêci.
MySQL
W dziedzinie obs³ugi bazy danych MySQL dokona³o siê wiele powa¿-
nych zmian. W PHP5 do dyspozycji mamy teraz dwa rozszerzenia do
obs³ugi MySQL:
!
mysql, czyli stara proceduralna biblioteka do obs³ugi MySQL,
!
mysqli, czyli ca³kowicie nowa biblioteka obs³uguj¹ca zarówno
paradygmat obiektowy, jak i proceduralny, przeznaczona do pra-
cy z baz¹ MySQL 4.1 lub nowsz¹.
Nowoœci zwi¹zane z rozszerzeniem mysqli:
!
zapytania przygotowane (prepared statements),
!
mo¿liwoœæ wykonywania wielu zapytañ przy u¿yciu jednej funkcji
(multi-querying),
!
bezpieczne po³¹czenia przy u¿yciu SSL.
Instalacja mysqli
By zainstalowaæ rozszerzenie mysqli w œrodowisku Windows nale¿y:
1. OdnaleŸæ plik konfiguracyjny php.ini (ulokowany najczêœciej
w katalogu z instalacj¹ PHP) i edytowaæ go.
2. Poszukaæ sekcji: „Dynamic Extensions”, a nastêpnie linii:
„;extension=ext/php_mysqli.dll”.
3. Usun¹æ œrednik (znak komentarza) i zapisaæ plik.
4. Przekopiowaæ plik „libmysqli.dll” z g³ównego katalogu z instalacj¹
PHP do katalogu „system32” (najczêœciej c:\windows\system32\).
5. Zrestartowaæ/uruchomiæ serwer Apache.
6. Sprawdziæ za pomoc¹ funkcji phpinfo(), czy rozszerzenie zosta³o
poprawnie za³adowane (czy widnieje na liœcie zainstalowanych
rozszerzeñ).
mysqli
Nowa biblioteka do obs³ugi bazy MySQL to odpowiedŸ na wzrastaj¹ce mo¿-
liwoœci MySQL. G³ównymi zaletami nowego, udoskonalonego rozszerzenia
jest przede wszystkim wiêksza wydajnoœæ, nawet 40-krotnia w porównaniu ze
starym rozszerzeniem. Dzieje siê tak za spraw¹ przepisanego od nowa kodu.
Interesuj¹co prezentuj¹ siê te¿ mo¿liwoœci obiektowego interfejsu mysqli,
bowiem ka¿d¹ z trzech klas interfejsu mo¿na rozszerzaæ poprzez dziedzicze-
nie. Mo¿liwe jest te¿ stworzenie w³asnej, efektywniejszej obs³ugi b³êdów.
Jak zapewniaj¹ autorzy nowego rozszerzenia mysqli, tak¿e i bez-
pieczeñstwo uleg³o radykalnej zmianie. Stary system wymiany hase³
miêdzy baz¹ a klientem zosta³ przebudowany i jest odporny na ataki
niczym protokó³ SSH. Nie bez znaczenia dla bezpieczeñstwa jest tak¿e
mo¿liwoœæ tworzenia zapytañ przygotowanych. Utrudniaj¹ one znacz-
nie tworzenie ataków typu „SQL Injection” (wiêcej o typach ataków
w artykule „Bezpieczeñstwo PHP” – MI 2/2004).
PHP
INTERNET.listopad.2004
101
WARSZTAT
PROGRAMY
MAGAZYN
FIRMA
Z OK£ADKI
NEWSY
NA CD
"
C
M
Y
K
Przejœcie z jednego rozszerzenia na drugie jest bardzo proste. Je¿eli
porównaæ interfejsy proceduralne obu rozszerzeñ, to s¹ one bardzo do
siebie zbli¿one:
<?php
$conn = mysqli_connect(’localhost’, ’user’,
!
’password’, ’test’);
if(!$conn)
die();
$query = mysqli_query($conn, ’SELECT a, b FROM
!
jakastabela ORDER BY id LIMIT 5’);
while($data = mysqli_fetch_assoc($query)) {
print_r($data);
}
echo mysqli_affected_rows($conn);
mysqli_close($conn);
?>
Jak ³atwo dostrzec, nowe rozszerzenie ró¿ni siê tylko symbolicznie.
Przejœcie ze starego na nowe powinno wiêc byæ ³atwe, o ile zadbamy o:
!
przemianowanie funkcji z mysql_ na mysqli_,
!
wstawienie uchwytu po³¹czenia jako parametru wymaganego.
Interfejs obiektowy
Przyjrzyjmy siê teraz przyk³adowi, który zrobi dok³adnie to samo, lecz
tym razem skorzystamy z interfejsu obiektowego:
<?php
$conn = new mysqli(’localhost’, ’user’,
!
’password’, ’test’);
if(!$conn)
die();
$query = $conn->query(’SELECT a, b FROM
!
jakastabela ORDER BY id LIMIT 5’);
while($data = $query->fetch_assoc()) {
print_r($data);
}
echo $conn->affected_rows;
$conn->close();
?>
W pierwszej kolejnoœci tworzymy nowy obiekt, podaj¹c mu za pa-
rametry wszystkie dane dotycz¹ce po³¹czenia. Nastêpnie wywo³ujemy
metodê query() i nie istnieje ju¿ potrzeba przekazywania uchwytu.
Przy metodzie fetch_assoc() nale¿y zwróciæ uwagê na to, ¿e operuje-
my ju¿ na zupe³nie innym obiekcie. Nie jest to, jak poprzednio, obiekt
$conn, lecz obiekt $query. W interfejsie obiektowym rozszerzenia my-
sqli dysponujemy bowiem trzema klasami:
!
klasa mysqli jest wykorzystywana do nawi¹zywania relacji miê-
dzy PHP ó MySQL,
!
klasa mysql_result pozwala na obs³ugê wyników (st¹d
fech_assoc(), korzysta z obiektu $query, utworzonego przez
metodê query() obiektu $conn),
!
klasa mysql_stmt dedykowana jest zapytaniom przygotowanym.
Przejœcie ze starego interfejsu proceduralnego na nowy interfejs
obiektowy bêdzie wymaga³o znacznie wiêcej pracy, ni¿ przejœcie ze
starego na nowy interfejs proceduralny. Dlatego te¿ interfejs obiekto-
wy przewidziany jest do stosowania w oprogramowaniu (skryptach)
pisanym ca³kowicie od nowa.
Zapytania przygotowane
Wraz z rozszerzeniem mysqli wprowadza siê pojêcie zapytania przy-
gotowanego, które do tej pory by³o nieznane programistom operuj¹-
PHP
INTERNET.listopad.2004
102
NA CD
NEWSY
Z OK£ADKI
FIRMA
MAGAZYN
PROGRAMY
WARSZTAT
!
KLASA
NAZWA
OPIS
ZWRACA
mysqli
affected_rows
właściwość zwraca ilość zmian dokonanych w rekordach
mixed
przy wykorzystaniu zapytań z rodziny INSERT, UPDATE lub DELETE.
mysqli
autocommit(bool tryb)
metoda włącza lub wyłącza auto−commit
bool
mysqli
close()
metoda zamyka połączenie z bazą
bool
mysqli
commit()
metoda zatwierdza bieżącą transakcję
bool
mysqli
connect(*)
metoda otwiera nowe połączenie z bazą danych
obiekt (połączenie)
mysqli
errno
właściwość zwraca kod błędu ostatniego błędnego zapytania
integer
mysqli
error
właściwość zwraca opis błędu dokonanego
string
w ostatnim błędnym zapytaniu
mysqli
field_count
właściwość zwraca ilość kolumn zwróconych
integer
przez ostatnie dokonane zapytanie
mysqli
info()
metoda dostarcza informacji o ostatnio wykonanym zapytaniu
string
mysqli
insert_id
właściwość zwraca ID ostatnio utworzonego rekordu
0 lub integer ID
mysqli
mysqli(*)
konstruktor klasy mysqli; parametry są opcjonalne
obiekt (połączenie)
mysqli
prepare (string zapytanie)
metoda przygotowuje zapytanie do wykonania
obiekt stmt lub fałsz (jeżeli błąd)
mysqli
query (string zapytanie [, int tryb_wyniku])
wykonuje zapytanie na bazie danych
prawda/obiekt lub fałsz (jeżeli błąd)
mysqli
rollback()
metoda cofa aktualną transakcję
bool
mysqli
select_db (string baza)
metoda zmienia/wybiera bazę danych
bool
mysqli_stmt
bind_param(object stmt, string
metoda przypisuje wartości do wskazanego
bool
typy, mixed &dane1 [, mixed &...]))
przygotowanego zapytania
mysqli_stmt
bind_result(object stmt, mixed
metoda przypisuje zmienne
bool
&dane1 [, mixed &...])
do przygotowanego zapytania
mysqli_stmt
close()
metoda zamyka przygotowane zapytanie
bool
mysqli_stmt
execute(object stmt)
metoda wykonuje przygotowane zapytanie
bool
mysqli_stmt
prepare (string zapytanie)
metoda przygotowuje zapytanie do wykonania
obiekt stmt lub fałsz (jeżeli błąd)
mysqli_result
fetch_array([int typ wyniku])
zwraca numeryczną, asocjacyjną lub numeryczną
tablica lub NULL
i asocjacyjną tablicę z wierszem wyników
mysqli_result
fetch_assoc()
zwraca tablicę asocjacyjną z wierszem wyników
tablica asocjacyjna lub NULL
mysqli_result
fetch_field()
na podstawie wyniku zapytania zwraca informację
obiekt lub fałsz
o kolejnej kolumnie w postaci obiektu
mysqli_result
fetch_fields()
ma podstawie wyniku zapytania zwraca informację
tablica obiektów lub fałsz
o kolumnach w postaci obiektu
mysqli_result
fetch_object()
zwraca wiersz wyników w postaci obiektu wypełnionego danymi
obiekt lub NULL
mysqli_result
fetch_row()
zwraca tablicę numeryczną z wierszem wyników
tablica lub NULL
mysqli_result
free()
czyści z pamięci dane związane z wynikiem
void
* – [string host [, string uzytkownik [, string haslo [, string baza [, int port [, string gniazdo]]]]]]
cym na bazie MySQL, a doskonale znane u¿ywaj¹cym baz Oracle.
Idea tego rodzaju zapytañ jest prosta, a zarazem skuteczna. Przy ich
u¿yciu mo¿emy tworzyæ zapytania przygotowane oparte o praktycznie
wszystkie elementy jêzyka SQL. Najczêœciej z zapytañ przygotowa-
nych korzysta siê przy wprowadzaniu danych (INSERT), ich aktuali-
zacji (UPDATE), ale tak¿e przy pobieraniu (SELECT) i usuwaniu
(DELETE).
Gdy tworzymy zapytanie typu INSERT, do sekcji VALUES wpro-
wadzamy informacje, które chcemy dodaæ do tabeli. Podobne zapyta-
nie powtarzamy tyle razy, ile informacji mamy do dodania. Przy czym
za ka¿dym razem do sekcji VALUES wprowadzamy inne dane. Tak
podstêpujemy, gdy chcemy wprowadziæ jakieœ dane do bazy:
INSERT INTO jakastabela (a, b) VALUES (’abcd’, ’1.24’)
INSERT INTO jakastabela (a, b) VALUES (’efgh’, ’6.32’)
Gdybyœmy miejsca, które ulegaj¹ zmianie zast¹pili znakiem zapy-
tania, wygl¹da³oby to tak:
INSERT INTO jakastabela (a, b) VALUES (?, ?)
Zapytanie przygotowane jest to najogólniej mówi¹c szablon, do
którego póŸniej bêdziemy wprowadzali dane w miejsce znaków zapy-
tania. Powy¿szy przyk³ad wysy³amy do bazy danych MySQL, by mo-
g³a go sobie sprawdziæ na obecnoœæ b³êdów sk³adni i zapisaæ w spe-
cjalnym buforze. Z powrotem MySQL odda nam uchwyt do tego za-
pytania, byœmy go mogli póŸniej wykorzystaæ. Gdy zechcemy wpro-
wadziæ jakieœ dane do tabeli, wystarczy do bazy danych przes³aæ tylko
te dane, które wejd¹ w miejsce znaków zapytania.
Taka metoda dzia³ania daje spore korzyœci. Po pierwsze baza da-
nych nie musi za ka¿dym razem sprawdzaæ zapytania na obecnoœæ b³ê-
dów. Wystarczy, ¿e zrobi to raz, bo zapytanie siê nie zmienia. Zmianie
ulegaj¹ tylko te dane, które wprowadzamy za pomoc¹ znaków zapyta-
nia. Poniewa¿ dane te trafiaj¹ do bazy pozbawione pozosta³ej czêœci
zapytania, maj¹ mniejsz¹ objêtoœæ, a co za tym idzie mo¿na je przes³aæ
szybciej. Biblioteka mysqli przy wysy³aniu tych danych zoptymalizuje
je jeszcze odpowiednio, by jak najmniej zajmowa³y i jak najszybciej
dotar³y do bazy. Taki sposób wykonywania zapytañ cechuje siê ponad-
to zwiêkszonym bezpieczeñstwem. Mysqli samodzielnie zneutralizuje
znaki, które mog¹ byæ k³opotliwe, odci¹¿aj¹c programistê od tego obo-
wi¹zku.
Podsumowuj¹c: ogólna idea przemawiaj¹ca za stosowaniem zapy-
tañ przygotowanych to uzyskanie maksymalnego przyspieszenia przy
wykonywaniu serii zapytañ poprzez:
!
stworzenie szablonów zapytañ, które s¹ kompilowane i spraw-
dzane,
!
uzupe³nienie szablonów, co pozwala na nie przesy³anie pe³nego
zapytania, lecz tylko zmieniaj¹cych siê danych.
Efektem jest mniejsza iloœæ przes³anych danych pomiêdzy baz¹ da-
nych a klientem oraz wiêksza prêdkoœæ dzia³ania dziêki ju¿ skompilo-
wanym szablonom. Jak to wygl¹da na przyk³adzie kodu?
<?php
$conn = new mysqli(’localhost’, ’user’,
!
’password’, ’test’);
$dane[0][’a’] = ’wxyz’;
$dane[0][’b’] = 1.65;
$dane[1][’a’] = ’wxyz’;
$dane[1][’b’] = 1.65;
$stmt = $conn->prepare(’INSERT INTO
!
jakastabela (a, b) VALUES (?, ?)’);
foreach($dane as $d) {
$stmt->bind_param(’sd’, $d[’a’], $d[’b’]);
$stmt->execute();
}
?>
Dane, które mamy zamiar wprowadziæ do bazy danych, miesz-
cz¹ siê w tablicy $dane. W pierwszej kolejnoœci wykonujemy meto-
dê prepare(), która ma za zadanie przygotowaæ zapytanie do póŸ-
niejszego wykorzystania. Szablon posiada dwa znaki zapytania,
czyli o tyle¿ zmiennych zostanie uzupe³niony. Do przypisywania
parametrów zwi¹zanych s³u¿y metoda bind_param(). Drugi i ka¿dy
kolejny parametr oznaczaj¹ wartoœci, o które kolejno zostanie uzu-
pe³niony szablon w miejsce „?”. Pierwszy parametr to coœ nowego.
Definiuje on jakiego typu danych s¹ zmienne uzupe³niaj¹ce sza-
blon. Kolejne znaki odpowiadaj¹ typom danych kolejnych znaków
zapytania, czyli naszych zmiennych. Po co to wszystko? By biblio-
teka mysqli mog³a wybraæ najbardziej optymalny dla niej sposób
transmisji danych do bazy danych. Poszczególne litery t³umaczy siê
jako nastêpuj¹ce typy:
!
„i” – wszystkie typy INT,
!
„d” – DOUBLE i FLOAT,
!
„b” – BLOBy,
!
„s” – wszystkie pozosta³e typy.
Poniewa¿ pierwsza zmienna wprowadzana do tabeli jest ci¹giem
znaków, czyli stringiem, korzystamy z litery „s”. Skoro zaœ druga
zmienna to liczba zmiennoprzecinkowa, u¿ywamy litery „d”. Tak
powstaje pierwszy parametr metody bind_param(), czyli „sd”. Po
przypisaniu danych do zapytania mo¿na go wykonaæ za pomoc¹
metody execute(). W ten sposób pêtla wykona ³¹cznie dwa razy za-
pytanie, co spowoduje dodanie dwóch rekordów do bazy danych.
Przy czym nale¿y zwróciæ uwagê, ¿e pracujemy nie na klasie my-
sql, lecz na mysql_stmt. Moment w którym tworzymy obiekt tej
klasy to wywo³anie metody prepare(). Od tej linii kodu pracujemy
wy³¹cznie na obiekcie klasy mysql_stmt. Za³¹czona tabela prezen-
tuje wybrane metody i w³aœciwoœci wszystkich trzech klas do ob-
s³ugi MySQL.
Zapytania przygotowane – pobieranie wyników
Stworzenie zapytañ przygotowanych mo¿liwe jest równie¿ w przypad-
ku pobierania. Zobaczmy to na przyk³adzie pobierania danych przy
u¿yciu sk³adni polecenia SELECT:
PHP
INTERNET.listopad.2004
103
WARSZTAT
PROGRAMY
MAGAZYN
FIRMA
Z OK£ADKI
NEWSY
NA CD
"
C
M
Y
K
C
M
Y
K
PHP
INTERNET.listopad.2004
104
NEWSY
Z OK£ADKI
FIRMA
MAGAZYN
PROGRAMY
WARSZTAT
!
NA CD
<?php
$conn = new mysqli(’localhost’, ’user’,
!
’password’, ’test’);
$stmt = $conn->prepare(’SELECT a, b FROM
!
jakastabela ORDER BY id’);
$stmt->execute();
$stmt->bind_result($a, $b);
while($stmt->fetch()) {
echo $a.$b;
}
$stmt->close();
?>
Przygotowujemy typowe zapytanie za pomoc¹ metody prepare().
Jak ³atwo zauwa¿yæ, zapytanie to nie posiada znaków „?”. Dlacze-
go? Poniewa¿ nie bêdzie posiada³o ¿adnych innych wariantów. To
z kolei oznacza, ¿e za ka¿dym razem bêdziemy pobierali dane przy
u¿yciu tego samego zapytania. Zapytanie przygotowane wykonuje-
my, czyli przekazujemy za pomoc¹ metody execute() do serwera.
Nowoœci¹ w stosunku poprzednich przyk³adów jest metoda bind_re-
sult(), u¿ywana niejako zamiast bind_param(). Jej parametry
($a, $b) to kolejne kolumny z zapytania. Wiersz wyniku pochodz¹cy
z kolumny o nazwie „a” zostanie przypisany do zmiennej $a, wiersz
„b” do zmiennej $b. Metoda close() s³u¿y do oczyszczenia pamiêci
bazy z informacji na temat wskazanego zapytania przygotowanego.
Warto u¿yæ tej funkcji, by odci¹¿yæ bazê mo¿liwie jak najprêdzej.
O ile nie ma to wielkiego znaczenia przy ma³ych serwisach interne-
towych, o tyle ju¿ œrednie serwisy mog¹ odczuæ nieznaczny wzrost
wydajnoœci bazy.
Transakcje
Kolejnym narzêdziem, z którego warto skorzystaæ, jest mo¿liwoœæ do-
konywania transakcji na bazie MySQL. Zasadê dzia³ania transakcji
t³umaczy siê na przyk³adzie konta bankowego, bo to najprostszy, a za-
razem najbardziej obrazowy przyk³ad. Za³ó¿my wiêc, ¿e dokonujemy
transakcji pieniêdzy pomiêdzy klientem „a” a klientem „b”. Gdy prze-
lewamy klientowi „b” jakaœ sumê pieniêdzy, klientowi „a” musimy j¹
odj¹æ. Punkt po punkcie wygl¹da to tak:
1 – dodaj klientowi „b” kwotê x przelan¹ przez klienta „a”,
2 – odejmij klientowi „a” kwotê x przelan¹ do klienta „b”.
Do zrealizowania takiej operacji bankowej potrzebujemy wiêc
dwóch zapytañ. Co siê stanie, gdy jedna z tych operacji siê nie powie-
dzie z jakichkolwiek przyczyn? Z pewnoœci¹ ktoœ na tym straci. Jak
wiêc to powinno wygl¹daæ? Gdy baza dokona realizacji punktu 1,
a nastêpnie punktu 2, przelew pieniêdzy uznaje siê za zakoñczony suk-
cesem. Lecz gdy coœ zawiedzie i jeden z punktów nie bêdzie móg³ zo-
staæ zrealizowany, baza danych cofnie ca³¹ operacjê. Tak¹ metodê
dzia³ania nazywamy transakcj¹. Jest to wiêc niepodzielny zbiór pole-
ceñ, które musz¹ zostaæ wykonane wszystkie naraz lub nie mo¿e zo-
staæ wykonane ¿adne z nich.
Spróbujmy wiêc teraz zrealizowaæ przyk³adow¹ transakcjê przy
u¿yciu biblioteki mysqli. Przed tym jednak ma³a uwaga. Transakcji nie
uda siê wykonaæ, gdy korzystamy z tabel typu ISAM lub MyISAM. Te
typy nie obs³uguj¹ transakcji. By wykonaæ transakcjê, typ tabeli mo¿e-
my zmieniæ np. na InnoDB, a zrobimy to nastêpuj¹cym poleceniem:
ALTER TABLE ”jakastabela” TYPE = INNODB
Do utworzenia najprostszej transakcji wykorzystuje siê trzy metody:
!
autocommit(), która ustawiona na fa³sz rozpoczyna transakcjê; jest
to wiêc ekwiwalent komendy BEGIN – rozpocznij transakcjê,
!
commit() to metoda, która zatwierdza prawid³owoœæ przeprowa-
dzonej transakcji – wszystko OK, transakcja zakoñczy³a siê suk-
cesem, zapomnij o niej,
!
rollback() cofa wszystkie zapytania, które zosta³y wykonane pod-
czas transakcji – uniewa¿nia transakcjê.
Zobaczmy wszystkie metody w akcji:
<?php
$conn = new mysqli(’localhost’, ’user’,
!
’password’, ’test’);
$conn->autocommit(false);
$a = $conn->query(’INSERT INTO jakastabela
!
(a, b) VALUES (”defg”, 1.32)’);
$b = $conn->query(’INSERT INTO jakastabela
!
(a, b) VALUES (”hijk”, 3.35)’);
$c = $conn->query(’INSERT INTO jakastabela
!
(a, b) VALUES (”lmno”, 2.97)’);
if($a & $b & $c) {
echo ’ok!’;
$conn->commit();
}
else {
echo ’b³¹d!’;
$conn->rollback();
}
?>
By rozpocz¹æ transakcjê, nale¿y wy³¹czyæ (!) metodê auto-com-
mit(), ustawiaj¹c j¹ na wartoœæ fa³sz. Nastêpnie mo¿emy ju¿ wykonaæ
interesuj¹ce nas zapytania w transakcji. By nieco u³atwiæ przyk³ad, do
ka¿dego wyniku metody query() przypisano jedn¹ zmienn¹. Jak wia-
domo, metoda query() zwraca prawdê, gdy zapytanie typu INSERT siê
powiedzie, a fa³sz, gdy nast¹pi jakiœ b³¹d. Mo¿emy dziêki temu spraw-
dziæ czy wszystkie zapytania zosta³y zrealizowane poprawnie, poprzez
wykonanie iloczynu logicznego wszystkich wyników. Je¿eli zosta³y
wykonane poprawnie, finalizujemy transakcjê. Zatwierdzenie transak-
cji nastêpuje poprzez wykonanie metody commit(). Gdy któreœ z zapy-
tañ zwróci b³¹d, zostanie wykonana metoda rollback(), która cofnie
wszystkie operacje dokonane pocz¹wszy od ustawienia metody auto-
-commit() na fa³sz.
Prawid³owo skonstruowana transakcja napisana w paradygmacie
obiektowym powinna byæ obs³ugiwana przez zaawansowane mechani-
zmy obs³ugi b³êdów dostêpne wraz z PHP5. O nich szerzej mówiliœmy
w pierwszej czêœci artyku³u (MI 9/2004).
Tworzenie własnych metod
Rozszerzanie funkcjonalnoœci interfejsu obiektowego mysqli jest jak
najbardziej mo¿liwe i wcale nie trudne do stworzenia. Za rozszerzanie
funkcjonalnoœci nale¿y rozumieæ mo¿liwoœæ utworzenia nowych funk-
cji, które zrealizuj¹ te bardziej kompleksowe zadania, z których jednak
korzystamy na tyle czêsto, by warto je by³o tworzyæ. Spójrzmy wiêc
na poni¿szy przyk³ad:
<?php
class my_mysqli extends mysqli
{
function array_id($id, $table) {
$query = sprintf(’SELECT * FROM %s WHERE
!
id = ”%d”’, $table, $id);
return $this->query($query)->fetch_assoc();
}
}
$conn = new mysqli(’localhost’, ’user’,
!
’password’, ’test’);
print_r($conn->array_id(’21’, ’jakastabela’));
?>
W przyk³adzie rozszerzyliœmy klasê mysqli klas¹ my_mysqli.
Zawiera ona jedn¹ metodê utworzon¹ na nasze potrzeby. Metoda ta
– array_id() posiada dwa parametry wejœciowe, które nastêpnie trafiaj¹
do zapytania. Odpowiedzi¹ metody jest tablica asocjacyjna z wynika-
mi. Ostatnia linia przyk³adu demonstruje w jaki sposób mo¿emy póŸ-
niej skorzystaæ z utworzonej funkcji pomocniczej.
Podsumowanie
W pierwszym artykule z serii zosta³ omówiony nowy silnik Zend
Engine 2.0. Zainstalowaliœmy now¹ wersjê PHP5 na domowym ser-
werze, a nastêpnie poznaliœmy specyfikatory dostêpu, klasy i meto-
dy abstrakcyjne, interfejsy, s³owo kluczowe final, konstruktory
i destruktory, sta³e wewn¹trzklasowe, w³aœciwoœci i metody sta-
tyczne, w³aœciwoœæ instanceof, funkcjê __autoload(), przeci¹¿anie
metod, metody __get i __set, sta³¹ __METHOD__ oraz zagadnienia
zwi¹zane z przestrzeniami nazw. W drugiej czêœci artyku³u dokoñ-
czyliœmy pojêcia zwi¹zane z nowym silnikiem obiektowym. By³o
o klonowaniu obiektów oraz o zaawansowanym mechanizmie ob-
s³ugi wyj¹tków throw/try/catch. Druga czêœæ artyku³u w przewa¿a-
j¹cej czêœci obejmowa³a zagadnienia zwi¹zane z obs³ug¹ XML.
PHP5 zaimponowa³ now¹ bibliotek¹ do obs³ugi XML, Simple
XML, która jest rzeczywiœcie prosta w obs³udze. Powiedzieliœmy
o XPath w SimpleXML oraz o obs³udze RSS przez SimpleXML.
Nastêpny fragment artyku³u by³ opisem odœwie¿onej biblioteki
DOM, wraz z jej mo¿liwoœciami i problematyk¹. Tak dobrnêliœmy
do trzeciej czêœci, która skupi³a siê na obs³udze baz danych przez
PHP5. Zosta³ omówiony nowy, obiektowy interfejs MySQL o na-
zwie mysqli oraz interfejs obiektowy SQLite. Trzecia czêœæ artyku-
³u by³a ju¿ ostatni¹ czêœci¹ kursu wprowadzaj¹cego w nowoœci
zwi¹zane z pi¹t¹ ods³on¹ PHP i stanowi praktyczny komplet pod-
stawowych informacji na temat PHP5.
n
PRZYDATNE ODNOŚNIKI
http://php.net/mysqli
– oficjalna dokumentacja rozszerzenia MySQLi
– Improved MySQL Ext.
http://php.net/sqlite
– oficjalna dokumentacja biblioteki plikowej bazy
danych SQLite
http://dev.mysql.com/doc/mysql/en/Installing.html
– oficjalna dokumen−
tacja wyjaśniająca jak zainstalować bazę MySQL
PHP
INTERNET.listopad.2004
105
WARSZTAT
PROGRAMY
MAGAZYN
FIRMA
Z OK£ADKI
NEWSY
NA CD
"
C
M
Y
K
str_split()
Konwertuje ciąg znaków na tablicę numeryczną. Jako pierwszy parametr po−
dajemy ciąg znaków, który chcemy przekształcić na tablicę numeryczną.
Drugi, opcjonalny parametr to liczba, która ustala co ile znaków ma nastąpić
podzielenie ciągu znaków na elementy tablicy. Wartością domyślną parame−
tru drugiego jest 1. Oznacza to, że ciąg znaków zostanie zamieniony na tyle
elementów tablicy, ile znaków występuje w tym ciągu.
Sposób implementacji:
array str_split (string ci¹g_znaków
!
[, int szerokoœæ_ciêcia])
Przykład:
<?php
$string = ”Jakiœ tekst”;
$array1 = str_split($string);
print_r($array1);
$array2 = str_split($string, 4);
print_r($array2);
?>
Wynik:
Array
(
[0] => J
[1] => a
[2] => k
[3] => i
[4] => œ
[5] =>
[6] => t
[7] => e
[8] => k
[9] => s
[10] => t
)
Array
(
[0] => Jaki
[1] => œ te
[2] => kst
)
strpbrk()
Przeszukuje ciąg znaków, sprawdzając czy nie występuje w nim jeden ze
wskazanych jako parametr znaków. Jeżeli występuje, wyświetli ciąg znaków
począwszy od odnalezionego znaku. Gdy nie znajdzie w ciągu znaków żad−
nego z poszukiwanych znaków, zwróci fałsz.
Sposób implementacji:
string strpbrk (string stóg_siana, string lista_znaków)
Przykład:
<?php
$string = ’Jakiœ tekst’;
echo strpbrk($string, ’ ’);
echo strpbrk($string, ’ke’);
?>
Wynik:
tekst
kiœ tekst
time_nanosleep()
Opóźnia wykonanie programu o podaną ilość sekund i nanosekund. Infor−
macje te podaje się kolejno jako pierwszy i drugi parametr. W przypadku po−
wodzenia funkcja zwraca prawdę, w przypadku błędu zwraca fałsz.
Sposób implementacji:
mixed time_nanosleep (int sekundy, int nanosekundy)
Przykład:
<?php
time_nanosleep(0, 500000)
?>
Wynik: skrypt „zasypia” na pół sekundy.
Nowe funkcje w PHP5