❕ Tato složka obsahuje podklady k domácímu studiu. Oproti běžným podkladům ke cvičením zde naleznete podrobnější vysvětlení dané problematiky a další příklady.
👉
V rámci minulého cvičení byla dokončena problematika používání objektů v PHP, druhá část podkladů pak byla věnována problematice validace formulářů.
👉
Z hlediska práce s objekty byste si měli pamatovat:
- již ze 3. cvičení základní informace o definici a používání tříd, jmenných prostorů, rozhraní, dědičnosti, traitů
- z minulého cvičení navíc magické metody:
- všechny začínají na __ (dvě podtržítka)
- jsou volány buď v případě speciálních úkonů (konstruktor, převod na string, serializace),
- nebo umí simulovat neexistující/zpřístupnit private proměnné či metody.
- classloader a composer:
- běžně nenačítáme soubory s definicí tříd ručně pomocí require/include, ale definujeme funkci, která je načte při jejich prvním použití;
- buď ruční definice pomocí
spl_autoload_register
, - nebo načítání v rámci nějakého frameworku.
- buď ruční definice pomocí
- závislosti načítáme nástrojem composer
- definice pomocí jednoduchého JSON souboru, ve kterém uvedeme, jaké komponenty chceme;
- composer načítá komponenty buď z https://packagist.org, nebo z GITu;
- pro načtení všech příslušných tříd stačí načíst vygenerovaný autoload.php.
- běžně nenačítáme soubory s definicí tříd ručně pomocí require/include, ale definujeme funkci, která je načte při jejich prvním použití;
👉
Z hlediska validace formulářů:
- musíme kontrolovat všechna data získaná od uživatele (ať jsme je získali z formuláře, v parametrech v URL či například z nějakého API)!
- u formuláře je sice hezké definovat kontrolu v HTML 5 a v javascriptu, ale stejně musíme kontrolovat data i na serveru,
- uživateli musíme zobrazit konkrétní popisy chyb (buď na jednom místě, nebo u konkrétních polí formuláře), správná data musí zůstat ve formuláři vyplněna;
- po odeslání formuláře metodou POST musí následovat přesměrování pomocí
header('Location: soubor.php');
🏠
Připomínám, že součástí byl také domácí úkol. Pokud jej máte hotový, nezapomeňte na jeho odevzdání.
👉
Na tomto cvičení nás čeká:
- opakování základních SQL příkazů pro manipulaci s daty
- vlastnosti MySQL a MariaDB
- databáze na serveru eso.vse.cz
- práce s nástrojem phpMyAdmin a jiné přístupy k databázi
- připojení k databázi z PHP
- tvorba aplikace využívající databázi
👉
Předpokládám, že za sebou máte základní kurz věnovaný databázím, tj. SQL v zásadě umíte a základní vlastnosti relačních databází znáte.
Budeme používat databázi MariaDB, jejíž SQL je v zásadě stejné, jako příkazy pro Oracle, se kterým už jste pracovali.
Co po vás budu chtít?
- příkazy pro CRUD operace, tj.
SELECT
,INSERT
,UPDATE
,DELETE
- umět logicky navrhnout strukturu databáze (naklikat ji)
- vědět, jak se chovají cizí klíče
- vědět, co jsou to transakce
Co po vás naopak chtít nebudu?
- vytváření a úprava tabulek, views atp.
- protože strukturu databáze většinou definujeme jen při vývoji aplikace a máme možnost si to naklikat v phpMyAdminu
- definice triggerů a dalších pokročilých funkcionalit (samozřejmě je můžete používat, ale jde to i bez nich)
👉
Pro jednoduché ověření - zvládli byste říct, co dělají následující příkazy?
SELECT * FROM osoby;
SELECT jmeno, prijmeni FROM osoby LEFT JOIN zamestnani ON osoby.id=zamestnani.osoba WHERE stav=1 ORDER BY prijmeni, jmeno LIMIT 10 OFFSET 100;
INSERT INTO osoby(jmeno, prijmeni, stav) VALUES ('Pepa', 'Novák', 1);
UPDATE osoby SET stav=0 WHERE prijmeni LIKE '%Nov%';
DELETE FROM osoby WHERE stav=0;
TRUNCATE TABLE osoby;
📘
- SQL turoriál na w3schools.com
- pár komentovaných příkladů:
👉
- MySQL a MariaDB jsou patrně nejčastěji používanými databázemi v kombinaci s PHP.
- Z historického hlediska se MySQL rozšířilo z důvodu svobodné licence, jednoduchosti a rychlosti.
- Databáze se obvykle instalovala rovnou v kombinaci s Apachem a PHP.
- Původně jednoduchá tabulková databáze, která dokonce neuměla ani cizí klíče.
- Dneska jde o plnohodnotnou a výkonnou databázi, která podporuje všechny běžné složitější konstrukty (např. triggery, relační integritu atp.)
- MySQL je majetkem Oracle, MariaDB je její nástupnickou open source větví. Pro malé aplikace mezi nimi však není vlastně žádný rozdíl.
👉
Na serveru eso.vse.cz máte každý zřízenou osobní databázi. Heslo pro připojení k ní najdete po přihlášení na server ve svém domovském adresáři, v souboru mysql-heslo.txt. Připojte se tedy k serveru a stáhněte/zkopírujte si heslo. Následně jej použijeme jak pro přihlášení pomocí phpMyAdminu, tak také ve vlastní aplikaci.
❕ Jako první operaci po připojení k databázi bude potřeba změnit její výchozí kódování na utf8mb4.
👉
Při vytváření tabulek je nutné si vybrat úložiště. Konkrétně se v praxi používají 2:
- InnoDB = úložiště s podporou cizích klíčů, doporučuji jej používat jako základní
- MyISAM = úložiště, které podporuje fulltextové indexy, ale nepodporuje cizí klíče; historicky bylo rychlejší, než InnoDB, dnes už je to srovnatelné
👉
Při vytváření sloupců v tabulkách máme na výběr několik základních datových typů. Když vytváříte tabulku v phpMyAdminu (viz dále), tak vám zobrazí nápovědu, k čemu se který datový typ hodí.
- INT = základní typ pro celá čísla
- FLOAT, DOUBLE = desetinná čísla s plovoucí desetinnou částkou
- DECIMAL = číslo s pevným počtem desetinných míst -> vhodné pro částky
- VARCHAR = textový řetězec o maximálně zadané délce; pokud je řetězec kratší, zabere v paměti jen tolik místa, kolik nutně potřebuje
- TEXT = datový typ pro velká textová data
- DATE = datum ve tvaru yyyy-mm-dd
- TIMESTAMP = klasický timestamp, jeho specialitou je to, že se jeden sloupec s tímto typem umí automaticky aktualizovat při každé změně v daném řádku (tj. hodí se to pro automatické sledovní poslední změny záznamu)
- ENUM, SET = datové typy s konkrétním výčtem hodnot -> vhodné např. pro pohlaví, stavy objednávky atp. Rozhodně je vhodnější používat ENUM nebo SET, než např. stavy objevnávky mít označené číslem.
Specifika datových typů:
- MariaDB nezná datový typ BOOLEAN. Místo něj používá INT(1), do kterého pak ukládáte 1 nebo 0.
- Pokud budete chtít v některém sloupci NULL hodnoty, musíte je extra povolit.
👉
Pozor na kódování!
- Specifikem MariaDB je to, že každá tabulka i každý její sloupec může používat jiné kódování. V praxi to ale neděláme, pokud to není vyloženě nutné, protože pak musíme všechny dotazy i jejich odpovědi překódovávat!
- Doporučuji používat MariaDB normálně s kódováním utf8, způsob řazení si pak můžete vybrat z dané nabídky. Např. utf8mb4_czech_ci.
👉
Typy indexů/klíčů
- PRIMARY = primární klíč tabulky
- UNIQUE = vyžadování unikátních hodnot, ale nejde o primární klíč
- INDEX = běžné indexování hodnot
- FULLTEXT = klíč s fulltextovým indexem
Klíče můžete definovat nad jedním či nad více sloupci, stejně jako v Oracle.
❕ Jedna praktická rada: Ačkoliv jste se v databázích učili, že když je to možné, máte používat složené klíče, ve webových aplikacích občas "zbytečně" zavádíme umělé primární klíče s autoincrementem. Důvody jsou poměrně jednoduché:
- v odkazech atp. vypadá mnohem lépe a srozumitelněji jedno číslo, než několik různých hodnot
- neměli bychom uživatelům ukazovat hodnoty, které nepotřebují vidět (např. osobní údaje osob atp.)
👉
- phpMyAdmin je komplexní webový nástroj pro práci s MySQL/MariaDB, přičemž je napsaný v PHP a nalezneme ho na většině serverů
- umožňuje nám jednoduše prohlížet a upravovat nejen data, ale i strukturu databáze
- phpMyAdmin na serveru eso najdete na adrese https://eso.vse.cz/phpmysqladmin
📙
👉
K databázi můžete samozřejmě přistupovat nejen pomocí phpMyAdminu, ale také pomocí IDE, konzole a spousty dalších nástrojů. Pro praktické použití uveďme alespoň 2 konkrétní příklady - Adminer a [připojení z konzole].
👉
- Jde o jednoduché rozhraní pro náhled do dabáze, zejména v situaci, kdy ji nechceme/nemůžeme zpřístupnit pomocí komplexnějšího nástroje.
- Obrovskou výhodou je to, že jde vlastně jen o jeden malý PHP soubor, který můžete nahrát na libovolný hosting s PHP.
- Kromě MariaDB podporuje i celou řadu dalších databází, včetně objektových.
- Nástroj má 2 varianty: Adminer a Adminer Editor - první z nich zpřístupňuje jen data, druhý umožňuje i naklikat strukturu databáze.
Doporučuji vám si tento nástroj vyzkoušet a zapamatovat, protože je to nejjednodušší možný způsob, jak se dostat do databáze, i když není přístupná mimo server.
📘
- oficiální web nástroje: https://www.adminer.org/cs/
- předinstalovaný Adminer na serveru eso.vse.cz
👉
Pokud máte k serveru přístup pomocí ssh, můžete využít také jednoduché připojení pomocí konzole mysql. Tato možnost je k dispozici i na serveru eso.vse.cz, jen pro připojení musíte být na VPN.
Pokud konzolové nástroje nemáte rádi, určitě vás nenutím, abyste následující postup zkoušeli.
Jak se připojit k serveru? K připojení k serveru buď můžete na použít ssh (na novějších verzích win 10 a všech unixových systémech), nebo na windows také nástroj Putty.
Připojení k serveru:
ssh [email protected] # připojit se na server eso s uživatelským jménem xname (následně se zobrazí výzva pro heslo)
Po připojení jste v normálním linuxovém terminálu (konzoli) - na serveru eso.vse.cz jde o bash. Fungují tu tedy všechny běžné příkazy, např ls
pro výpis adresáře, cd
pro jeho změnu atd.
cat ~/mysql-heslo.txt # můžete si vypsat heslo k databázi
Až budete chtít připojení ukončit, spusťte příkaz
exit
Jak používat konzolové mysql?
Připojíme se ke konzoli MySQL/MariaDB:
mysql -pHESLO xname # připojení k databázi (název databaze je stejný jako vaše xname). POZOR, mezi -p a heslem není žádná mezera!
Při zadání správného jména a hesla jste přihlášeni do databáze a můžete přímo zadávat SQL příkazy. Například:
SHOW TABLES;
SELECT * FORM table;
Nakonec se nezapomeňte odhlásit pomocí:
exit;
👉
Připojení k MySQL/MariaDB je z PHP možné hned několika metodami. Mezi běžné způsoby lze zařadit:
- připojení pomocí PDO
- tento způsobu doporučuji, jde o standardní variantu
- s touto možností budeme řešit příklady na cvičeních
- připojení pomocí mysqli funkcí
- pozor, je opravdu nutné používat funkce začínající na mysqli (ne na mysql)
- musíte ručně escapovat speciální znaky v dotazech
👉
Kromě přímého připojení můžete využít také nějakou abstraktní vrstvu - ať již pro jednodušší tvorbu dotazů, nebo pro objektově relační mapování.
- Řada PHP frameworků či CMS v sobě obsahuje i databázovou vrstvu:
- v Zendu, Nette atp. můžete buď používat připojení pomocí tříd frameworku, nebo použít libovolný jiný způsob připojení (např. s ORM);
- vlastní připojení najdete také v nejrozšířenějších CMS - např. ve wordpressu.
- Pro zjednodušení tvorby dotazů mohu doporučit např. dibi.
- Pro objektově-relační mapování lze používat např. Doctrine, nebo jednodušší Leanmapper.
👉
PDO, nebo také "PHP Data Objects", je univerzální rozhraní pro práci s databázemi z jazyka PHP. Ačkoliv jde o rozšíření, je dnes v podstatě na všech serverech (ostatně jako třeba JSON, XML atp.), protože nám výrazně usnadňuje vývoj.
V zásadě jde o základní abstrakční vrstvu, díky které nemusíme řešit, jaké konkrétní funkce pracují s daným typem databáze. Po instalaci příslušných ovladačů se můžeme dotazovat pořád stejně pomocí PDO. Je nutné ale mít na paměti, že:
- PDO nijak nemění SQL dotazy, které chceme spustit - tj. pokud chceme aplikaci převést např. z MariaDB do MS-SQL, budeme muset dotazy upravit (protože se dané varianty SQL neshodují);
- ovladače pro MariaDB/MySQL najdeme většinou rovnou nainstalované, ale např. pro Oracle obvykle ne. PDO se ale umí připojit k databázi i pomocí ODBC.
- Nad PDO je postaveno také velké množství vyšších abstraktních vrstev a knihoven, např. pro ORM.
📘
👉
Pro připojení k databázi stačí vytvořit instanci třídy PDO s příslušnými parametry.
- Z praxe doporučuji si danou proměnnou pojmenovat tak, aby bylo na první pohled zřejmé, o co jde. Např.
$db
nebo$pdo
. - K jedné databázi se připojujeme vždy jen jednou!
- V opačném případě bychom zbytečně zabíraly sockety pro možná připojení a zároveň výrazně zpomalovali skript.
- Pokud je na databázi postavená celá aplikace,
- Odpojení od databáze nijak řešit nemusíte, dojde k němu při zrušení databázového objektu. Tj. automaticky při konci aplikace.
❕ Doporučuji mít připojení k databázi definované v celé aplikaci jen v jednom souboru - buď rovnou vytvoření instance PDO, nebo nějaké konstanty s přístupy. Z bezpečnostních důvodů určitě časem dojde ke změně přístupů a rozhodně není rozumné hledat a měnit např. heslo k DB ve spoustě různých souborů.
//připojení do DB na serveru eso.vse.cz - XNAME a HESLO samozřejmě zaktualizujte dle svých vlastních údajů
//doporučuji do connection stringu rovnou dopsat také údaje o kódování, ve kterém chceme s databází komunikovat
$db = new PDO('mysql:host=127.0.0.1;dbname=XNAME;charset=utf8', 'XNAME', 'VASE HESLO DO MYSQL');
//následující nastavení zařídí, abychom byla při chybě v SQL vyhozena standardní výjimka (exception)
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
👉
Jednoduché spuštění SQL dotazu bez požadavku na odpověď
Pokud chceme spustit SQL dotaz, u kterého neočekáváme žádné konkrétní výsledky, je nejjednodušší spustit jen pomocí metody exec()
.
$db->exec('TRUNCATE TABLE tabulka;');
👉
Spuštění SQL dotazu bez uživatelských vstupů
Pro získání dat pomocí SQL můžeme použít metodu query()
. Jejím výsledkem bude PDOStatement, pomocí kterého se dostaneme k výsledkům.
$result = $db->query('SELECT * FROM tabulka;');
$data = $result->fetchAll();
👉
SQL dotaz s parametry
Pokud chceme spustit SQL dotaz, ve kterém mají být zahrnuta nějaká data získaná od uživatele či z jiného potenciálně nebezpečného zdroje, tak z důvodu ochrany přes SQL injection použijeme prepared statement.
👉
První variantou je dotaz s pojmenovanými parametry:
$query = $db->prepare('SELECT * FROM osoby WHERE jmeno=:jmeno AND prijmeni=:prijmeni;');//nejprve si připravíme dotaz s parametry
$query->execute([//následně naplníme parametry dotazu konkrétními hodnotami a spustíme
':jmeno' => $jmeno,
':prijmeni' => $prijmeni
]);
Jméno každého z parametrů musí začínat dvojtečkou.
Kromě předání pole parametrů při spuštění dotazu bychom alternativně mohli připojit parametry také postupně, pomocí metod $query->bindParam()
a $query->bindValue()
.
👉
Druhou variantou je dotaz s nepojmenovanými parametry:
$query = $db->prepare('SELECT * FROM osoby WHERE jmeno=? AND prijmeni=?;');//nejprve si připravíme dotaz s parametry
$query->execute([
$jmeno,
$prijmeni
]);
V tomto případě je každý z parametrů označen otazníkem. Při jejich naplnění musíme dodržovat pořadí parametrů v poli podle toho, jak byly uvedeny v SQL.
👉
PDOStatement
Po spuštění jednoduchého dotazu pomocí metody query()
nebo na základě spuštění prepared statementu máme k dispozici instanci třídy PDOStatement, která nám následně umožní vyzvednout výsledky dotazu z databáze.
První variantou, která se hodí zejména v případě zpracování menšího množství dat, je jednorázové získání pole se všemi výsledky:
$query = $db->query('SELECT * FROM osoby;');
$osoby = $query->fetchAll(PDO::FETCH_ASSOC);//každý z řádků DB tabulky získáme v podobě asociačního pole; alternativně bychom mohli získat pole s číselnými indexy, nebo objekty
if (!empty($osoby)){
foreach ($osoby as $osoba){
echo $osoba['jmeno'];
}
}
👉
Druhou variantou je postupné načítání jednotlivých řádků:
$query = $db->query('SELECT * FROM osoby;');
while ($osoba = $query->fetch(PDO::FETCH_ASSOC)){ //načteme jeden řádek z výsledků SQL dotazu v podobě asociačního pole
echo $osoba['jmeno'];
}
$query = $db->query('SELECT * FROM osoby;');
while ($osoba = $query->fetchObject()){ //načteme jeden řádek z výsledků SQL dotazu v podobě objektu (jako parametr funkce fetchObject() je možné zadat i název třídy, jejíž instanci chceme)
echo $osoba->jmeno;
}
👉
V některých případech chceme hodnoty jen jednoho sloupce. Například když chceme jen získat IDčka povolených uživatelů:
$query = $db->query('SELECT id FROM osoby;');
$osobyIdArr = $query->fetchColumn(0); //pokud by sloupců ve výsledcích bylo víc, tak jen číselným parametrem určíme, který sloupec chceme
👉
Poslední základní variantou je to, že nás zajímá jen počet řádků výsledku. Například když chceme postupně načítat seznam osob, ale nejdřív chceme vypsat jejich celkový počet.
$query = $db->query('SELECT * FROM osoby;');
echo $query->rowCount();
📘
Další zdroje informací:
📙
V rámci praktické ukázky si projdeme tvorbu aplikace, která bude sloužit jako jednoduchá webová nástěnka s daty uloženými v databázi. Na nástěnce bude možné mít umístěné příspěvky přiřazené do kategorií, každý příspěvek bude mít svého autora.
🏠
Domácí úkol vychází z aplikace jednoduché webové nástěnky, jejíž tvorba byla ukázána v předchozím příkladu. Za domácí úkol máte možnost získat 3 body. Zatím nijak nerozlišujeme uživatelská práva, tj. ta do aplikace určitě doplňovat nemusíte.
- doplňte do aplikace možnost úpravy příspěvku
- doplňte do aplikace možnost zobrazit si příspěvky jen ze zvolené kategorie
Způsob a termín odevzdání:
- Vytvořenou aplikaci nahrajte na server eso.vse.cz a odkaz na ni odevzdejte v zadání DÚ v MS Teams.