Lehk² ·vod do tvorby databßzov²ch aplikacφ v prost°edφ PostgreSQL a PHP3

Tento dokument obsahuje zßkladnφ informace pot°ebnΘ pro tvorbu databßzov²ch aplikacφ s WWW rozhranφm. Jako databßzov² systΘm se pou₧φvß jednoduch² SQL server PostgreSQL. Pro dynamickΘ generovßnφ strßnek z databßze se pou₧φvß systΘm PHP3.

Na Φtenß°e nejsou kladeny ₧ßdnΘ zvlßÜtnφ nßroky. StaΦφ, kdy₧ ovlßdß jazyk HTML a zßklady prßce se systΘmem PHP3. Znalost jazyka SQL nenφ v∙bec na Ükodu, ale nenφ nezbytn∞ nutnß.

P°edtφm ne₧ zaΦneme programovat

I kdy₧ budeme vytvß°et aplikaci s WWW-rozhranφm, co₧ dnes jeÜt∞ nenΘ zdaleka b∞₧nΘ, jednß se v jßdru o klasickou databßzovou aplikaci. Proto by p°i tvorn∞ reßlnΘho systΘmu nem∞la chyb∞t fßze anal²zy, kdy podrobn∞ prostudujeme reßln² systΘm, jeho₧ obraz se bude v naÜem informaΦnφm systΘmu (databßzovΘ aplikaci) odrß₧et.

Tato fßze v₧dy sestßvß z vytvo°enφ datovΘho modelu, kter² popisuje vztahy mezi jednotliv²mi entitami. Z tohoto modelu takΘ vyΦteme jakΘ tabulky budou v databßzi, jakΘ budou primßrnφ klφΦe v jednotliv²ch tabulkßch, jakΘ jsou vztahy mezi tabulkami, jakß platφ integritnφ omezenφ atd.

Na rozebφrßnφ datovΘho modelovßnφ zde nenφ prostor. My si vÜe ukß₧eme na jednoduchΘ ·loze, kde si bez n∞j vystaΦφme. Pro slo₧it∞jÜφ systΘmy je vÜak d∙kladnß anal²za nezbytnß.

Ukßzkovß aplikace

Prßci s PostgreSQL a PHP3 si ukß₧eme na jednoduchΘm p°φklad∞. Vytvo°φme jednoduch² adresß°, kter² bude slou₧it k uchovßvßnφ jmen, e-mailov²ch adres a dat narozenφ kamarßd∙. Aplikace nßm umo₧nφ adresß° prohledßvat a prohlφ₧et, p°idßvat do n∞j novΘ ·daje, opravovat ·daje stßvajφcφ a neaktußlnφ ·daje mazat.

PostgreSQL

PostgreSQL je jednoduch² databßzov² SQL server. Poskytuje vÜak dostateΦnΘ prost°edky pro tvorbu naÜφ aplikace. Navφc je p°imo podporovßn systΘmem PHP3, co₧ se nßm bude za chvφli hodit.

PostgreSQL umo₧≥uje na jednom poΦφtaΦi pracovat s vφce databßzemi. Ka₧dß databßze pak m∙₧e obsahovat n∞kolik tabulek, kterΘ mohou, ale nemusφ, b²t navzßjem provßzßny. V²pis vÜech databßzφ ulo₧en²ch v systΘmu zφskßme pomocφ p°φkazu:

psql -l
Ka₧d² mßte k dispozici databßzi, jejφ₧ jmΘno odpovφdß vaÜemu u₧ivatelskΘmu jmΘnu. Pokud se chceme podφvat, jakΘ tabulky databßze obsahuje, pou₧ijeme p°φkaz:
psql jmΘno_databßze -c \\d
K samotnΘ prßci s databßzφ slou₧φ p°φkaz psql. Po jeho spuÜt∞nφ m∙₧eme pomocφ p°φkazovΘ °ßdky zadßvat SQL p°φkazy, kterΘ se majφ provΘst. Jako parametr programu se zadßvß jmΘno databßze, se kterou chceme pracovat. P°φkazovou °ßdku programu ukonΦφme pomocφ p°φkazu \q.

Vytvo°enφ novΘ tabulky

Nynφ si ukß₧eme vytvo°enφ naÜφ ukßzkovΘ tabulky. Nejprve spustφme prost°edφ PostgreSQL p°φkazem:
psql jmΘno_databßze
K vytvo°enφ novΘ tabulky v databßzi slou₧φ SQL p°φkaz create table. Jeho syntaxe je nßsledujφcφ:
create table jmΘno_tabulky (jmΘno_polo₧ky typ_polo₧ky, ... )
P°ehled nejb∞₧n∞jÜφch datov²ch typ∙ p°inßÜφ tabulka.

VybranΘ datovΘ typy MySQL
TypPopis
intcelΘ Φφslo
floatΦφslo s pohyblivou °ßdovou Φßrkou
varchar(n)textov² °et∞zec o maximßlnφ dΘlce n
datedatum ve tvaru RRRR-MM-DD
timeΦas ve tvaru HH:MM:SS

My vytvo°φme tabulku adresar se Φty°mi polo₧kami jmΘno, p°φjmenφ, e-mail a datum narozenφ.

create table adresar (jmeno varchar(15), prijmeni varchar(15), 
                      email varchar(40), narozen date);
D∙le₧it² je st°ednφk na konci, kter²m se odesφlajφ p°φkazy PostgreSQL k provedenφ.

O tom, ₧e se tabulka skuteΦn∞ vytvo°ila, se m∙₧eme p°esv∞dΦit pomocφ p°φkazu \d zadanΘho v prost°edφ programu psql.

P°idßnφ novΘho zßznamu do tabulky

P°φmo v programu psql m∙₧eme do databßze p°idßvat i novΘ zßznamy. K p°idßnφ novΘho zßznamu do tabulky s N polo₧kami slou₧φ v SQL p°φkaz insert into:
insert into jmΘno_tabulky values (hodnota1, ..., hodnotaN)
My do tabulky p°idßme informace o panu Novßkovi:
insert into adresar values ('Jan', 'Novßk', 
                            'Jan.Novak@mail.cz', '1965-08-25');
Obdobn²m zp∙sbem m∙₧eme p°idat i dalÜφ zßznamy. Vidφme, ₧e tento zp∙sob nenφ zrovna dvakrßt u₧ivatelsky p°φjemn² -- dobrß motivace pro vytvo°enφ snadno ovladatelnΘho WWW rozhranφ k tabulce.

V²b∞r a prohlφ₧enφ zßznam∙ v tabulce

K v²b∞ru a vypsßnφ zßznam∙ z tabulky slou₧φ p°φkaz select. Pokud chceme vypsat obsah celΘ tabulky, zadßme p°φkaz:
select * from jmΘno_tabulky
Obsah naÜφ tabulky si tedy m∙₧eme ov∞°it pomocφ:
select * from adresar;
Informace lze vybφrat i selektivn∞. Podmφnka, kterß musφ pro vybranΘ zßznamy platit, se uvßdφ za klφΦovΘ slovo where. P°φklady selektivnφch dotaz∙:
select * from adresar where prijmeni like 'Novßk';
select * from adresar where email = 'jkj@sorry.vse.cz';
select * from adresar where prijmeni = 'Prochßzka' and jmeno = 'Karel';
select * from adresar where prijmeni like 'Pro%';
Znak '%' mß ve vyhledßvacφm °et∞zci za operßtorem like specißlnφ v²znam -- nahrazuje libovolnou sekvenci znak∙.

RuÜenφ zßznam∙ v tabulce

K ruÜenφ zßznam∙ v tabulce slou₧φ p°φkaz delete from. Zßznamy, kterΘ chceme smazat, musφme urΦit podmφnkou v klauzuli where:
delete from jmΘno_tabulky where podmφnka
Aby byl zßznam, kter² chceme smazat, jednoznaΦn∞ identifikovßn, je v podmφnce vhodnΘ provΘst test pro primßrnφ klφΦ. Pokud v tabulce nenφ primßrnφ klφΦ definovßn (jako nap°. V tΘ naÜφ) m∙₧eme pou₧φt primßrnφ klφΦ, kter² vytvß°φ PostgreSQL automaticky. JmΘno atributu s tφmto Φφseln²m k≤dem je OID (Object Identifier). OID jednotliv²ch zßznam∙ m∙₧eme vypsat pomocφ p°φkazu:
select oid, * from adresar;
Praktickß ukßzka smazßnφ zßznamu, jeho₧ identifikaΦnφ Φφslo je 24003:
delete from adresar where oid=24003;

Zm∞na zßznamu v tabulce

Ke zm∞n∞ zßznamu slou₧φ p°φkaz update:
update jmΘno_tabulky set polo₧ka=hodnota, ... where podmφnka
Ten modifikuje vÜechny zßznamy, kterΘ vyhovujφ podmφnce. Pokud chceme m∞nit pouze jeden zßznam -- to je ostatn∞ nejtypiΦt∞jÜφ p°φklad -- je vhodnΘ jako podmφnku uvΘst test primßrnφho klφΦe (nebo OID) na jedineΦnou hodnotu:
update adresar set email="novak@ini.cz" where oid=18937;
P°φkaz zm∞nφ mailovou adresu u₧ivatele, kter² je v adresß°i veden pod identifikaΦnφm Φφslem 18937.

Smazßnφ celΘ tabulky

Pokud se nßm n∞jakß tabulka znelφbφ, m∙₧eme ji i s jejφm obsahem smazat pomocφ p°φkazu:
drop table jmΘno_tabulky
Dejte si na tuto operaci pozor. Tabulka je smazßna nenßvratn∞.

P°φstupovß prßva k tabulce

PostgreSQL umo₧≥uje nastavovßnφ p°φstupov²ch prßv pomocφ standardnφho SQL-p°φkazu grant. Aby nßm sprßvn∞ fungovaly vÜechny nßsledujφcφ ukßzky spoluprßce PHP s databßzφ, povolφme vÜechny operace v tabulce vÜem u₧ivatel∙m. V praxi samoz°ejm∞ musφme pro zabezpeΦenφ neoprßvn∞nΘho p°φstupu k dat∙m ud∞lat maximum.
grant all on jmΘno_tabulky to public;

PHP3

V PHP3 se pro komunikaci s databßzφ MySQL pou₧φvajφ funkce zaΦφnajφcφ na pg. P°ed ka₧dou komunikacφ se serverem je pot°eba se k n∞mu p°ipojit a po skonΦenφ prßce se zase odpojit. TypickΘ schΘma prßce s PostgreSQL v PHP3 tedy vypadß takto:
<? $conn = pg_Connect("localhost", "", "", "", "jmΘno_databßze")?>

    prßce s databßzφ

<? pg_Close($conn)?>
$conn je prom∞nnß, kterß identifikuje spojenφ vytvo°enΘ se serverem.

V²pis zßznam∙ z tabulky

Abychom mohli vypsat zßznamy z tabulky, musφme je nejprve vybrat pomocφ SQL p°φkazu select. V PHP mßme k dispozici funkci pg_exec(SQL_p°φkaz), kterß jako v²sledek vracφ v²sledek SQL p°φkazu.

V p°φpad∞ p°φkazu select je v²sledkem seznam zßznam∙. Funkce v tomto p°φpad∞ vracφ ukazatel na seznam zßznam∙. Tyto zßznamy jsou pak dßle p°φstupnΘ pomocφ dalÜφch funkcφ. P°φklad dotazu v PHP:

<?
    $result = pg_exec("select * from adresar");
?>
PoΦet zßznam∙, kterΘ jsou v²sledkem poslednφho dotazu, m∙₧eme zjistit pomocφ funkce pg_NumRows($result). Pon∞kud ucelen∞jÜφ ukßzka:
<?
    $conn = pg_Connect("localhost", "", "", "", "test");
    $result = pg_exec("select * from adresar");
    $pocet = pg_NumRows($result);
    echo "V tabulce adresar je $pocet zßznam∙.";
    pg_Close($conn);
?>
JednotlivΘ polo₧ky zßznam∙, kterΘ jsou v²sledkem dotazu, jsou p°φstupnΘ pomocφ funkce pg_Result(). Ta mß t°i parametry:
pg_Result($result, Φφslo_zßznamu, polo₧ka)
Poznamenejme, ₧e zßznamy jsou Φφslovßny od 0. Pokud bychom tedy cht∞li vypsat obsah celΘ tabulky adresar, m∙₧eme na strßnku za°adit nßsledujφcφ k≤d:
<?
    $conn = pg_Connect("localhost", "", "", "", "test");
    $result = pg_exec("select * from adresar");
    $pocet = pg_NumRows($result);
    echo "V tabulce adresar je $pocet zßznam∙.";
    echo "<P>";
    $i = 0;
    while ($i<$pocet):
        echo pg_Result($result, $i, "jmeno") . " " .
             pg_Result($result, $i, "prijmeni") . ", " .
             pg_Result($result, $i, "email") . ", " .
             pg_Result($result, $i, "narozen") . "<BR>";
        $i++;
    endwhile;
    pg_Close($conn);
?>
Ve smyΦce bychom mohli kolem dat z databßze umφstit nap°φklad HTML tagy pro vytvo°enφ tabulky a v²sledky tak prezentovat v p°ehlednΘ tabulce.

Pokud ji₧ nepot°ebujeme s v²sledkem dotazu dßle pracovat, je vhodnΘ uvolnit pam∞¥, ve kterΘ je v²sledek ulo₧en. To provedeme volßnφm funkce pg_FreeResult($result).

Pokud v²sledkem volßnφ funkce pg_exec() nenφ seznam zßznam∙ (nap°. po SQL p°φkazech update, delete nebo insert), vracφ funkce true. Pokud p°i provßd∞nφ SQL p°φkazu doÜlo k chyb∞, vrßtφ funkce hodnotu false.

PoΦet zßznam∙, kter²ch se dotklo provedenφ operace update, delete nebo insert, vracφ funkce pg_Affected_Rows().

P°idßnφ novΘho zßznamu do tabulky

P°edpoklßdejme, ₧e v prom∞nn²ch $jmeno, $prijmeni, $email a $narozen mßme ulo₧eny informace o Φlov∞ku, kterΘho chceme do adresß°e p°idat. Do prom∞nn²ch se ·daje mohly dostat nap°φklad z formulß°e, kter² vyplnil u₧ivatel. Strßnka, kterß tento formulß° obsluhuje, pak bude obsahovat tento k≤d pro p°idßnφ novΘho zßznamu do tabulky:
<?
    $conn = pg_Connect("localhost", "", "", "", "test");
    $result = pg_exec("insert into adresar values ('$jmeno', '$prijmeni', " +
	              "'$email', '$narozen')");
    if ($result):
        echo "Do adresß°e byl ·sp∞Ün∞ p°idßn nov² zßznam.";
    else:
        echo "A sakra! Nov² zßznam se do adresß°e nepoda°ilo p°idat.";
    endif;
    pg_Close($conn);
?>    

ZruÜenφ zßznßmu v tabulce

P°edpoklßdejme, ₧e identifikaΦnφ Φφslo zßznamu, kter² chceme smazat, mßme ulo₧eno v prom∞nnΘ $oid. Vymazßnφ pak v PHP provedeme takto:
<?
    $conn = pg_Connect("localhost", "", "", "", "test");
    $result = pg_exec("delete from adresar where oid=$oid");
    if ($result):
        echo "Zßznam se poda°ilo ·sp∞Ün∞ vymazat.";
    else:
        echo "Zßznam nelze vymazat, do povrchu pevnΘho disku je vyryt.";
    endif;
    pg_Close($conn);
?>    

Zm∞na zßznßmu v tabulce

P°edpoklßdejme, ₧e u Φlov∞ka, jeho₧ $oid znßme, chceme zm∞nit e-mailovou adresu na hodnotu prom∞nnΘ $email:
<?
    $conn = pg_Connect("localhost", "", "", "", "test");
    $result = pg_exec("update adresar set email='$email' where oid=$oid");
    if ($result):
        echo "Zßznam se poda°ilo ·sp∞Ün∞ aktualizovat.";
    else:
        echo "Zßznam nelze aktualizovat, do povrchu pevnΘho disku je vyryt.";
    endif;
    pg_Close($conn);
?>    

© Jirka Kosek, 1998