Geek tričko zdarma Geek tričko zdarma
Hledáme grafika na pohodovou brigádu v Blenderu nebo programátora na hry v PyGame. Máš zájem? Napiš nám na redakce [zavináč] itnetwork.cz!
Tričko zdarma! Stačí před dobitím bodů použít kód TRIKO15. Více informací zde

Lekce 3 - Formulář a výpis dat z databáze do tabulky v PHP

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, První databázová tabulka a MySQL ovladače v PHP, jsme se připojili k databázi a vložili do ní několik uživatelů. V reálných aplikacích se uživatelé vkládají pomocí formuláře. Přesně to se dnes naučíme a také se naučíme vypsat uživatele z databáze do HTML tabulky. Budeme pokračovat ve stylu co nejjednoduššího kódu.

Formulář

Pro vkládání uživatelů do databáze si vytvoříme jednoduchou HTML stránku s jedním formulářem. Náš vkládací dotaz upravíme tak, aby vkládal hodnoty z formuláře. Uveďme si kompletní kód registrační aplikace:

<!DOCTYPE html>
<html lang="cs-cz">

        <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
                <title>Registrace uživatele</title>
        </head>

        <body>

                <h1>Registrace uživatele</h1>

                <?php

                require_once('Db.php');
                Db::connect('127.0.0.1', 'databaze_pro_web', 'root', '');
                if ($_POST)
                {
                        $datum = date("Y-m-d H:i:s", strtotime($_POST['datum_narozeni']));
                        Db::query('
                                INSERT INTO uzivatele (jmeno, prijmeni, datum_narozeni)
                                VALUES (?, ?, ?)
                        ', $_POST['jmeno'], $_POST['prijmeni'], $datum);

                        echo('<p>Byl jste úspěšně zaregistrován.</p>');
                }
                ?>

                <form method="post">
                        Jméno:<br />
                        <input type="text" name="jmeno" /><br />
                        Příjmení:<br />
                        <input type="text" name="prijmeni" /><br />
                        Datum narození:<br />
                        <input type="text" name="datum_narozeni" /><br />
                        <input type="submit" value="Registrovat" />
                </form>

        </body>
</html>

Kód je stále velmi krátký. Vysvětleme si ho. Co se týče HTML, tak tam by mělo být vše jasné. Formulář je jednoduchý a obsahuje 3 pole (jméno, příjmení, datum narození) a odesílací tlačítko. Protože form postrádá atribut action, odešle se na tu samou stránku.

Ve stránce je rovněž PHP skript, který se připojí k databázi. Podmínkou otestuje, zda se odeslala nějaká data formulářem. Pokud ano, vykoná SQL dotaz, který data do databáze vloží. Všimněme si třech věcí:

  1. Datum musíme převést z českého formátu (tak, jak ho zadal do políčka uživatel, např. 15.1.1989) do formátu MySQL (např. 1989-15-1). To za nás udělá dvojice funkcí str_to_time() a date().
  2. SQL dotaz je velmi podobný tomu z minulého dílu. Již nevkládáme do všech sloupců, ale jen do třech. Do sloupce pocet_clanku se vloží výchozí hodnota, tedy 0.
  3. Do dotazu zde již potřebujeme vložit proměnné z PHP (konkrétně od uživatele z $_POST). A nyní pozor: Proměnné NIKDY! nevkládáme přímo do dotazu! Kdyby uživatel zadal místo jména nějaký SQL příkaz, tak by se totiž do dotazu vložil a provedl na naší databázi! Místo parametrů v dotazu vždy píšeme otazníky a potom parametry předáme ve stejném pořadí jako další parametry funkce Db::query()! Tuto chybu zde neustále opakují začátečníci stále a stále dokola, hazardujete se svými daty a daty vašich uživatelů!

Ukažme si ještě raději, jak se to nemá dělat:

// TENTO KÓD JE VELMI NEBEZPEČNÝ!
Db::query('
        INSERT INTO uzivatele (jmeno, prijmeni, datum_narozeni)
        VALUES ("'. $_POST['jmeno'] . '", "' . $_POST['prijmeni'] . '", "' . $datum . '")');
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Proměnné jsou vložené přímo v SQL dotazu. Když uživatel napíše do políčka pro jméno tento řetězec:

", "", ""); DELETE FROM uzivatele; --

Smaže nám všechny uživatele v databázi, protože co napsal se vloží přímo do dotazu a příkaz se vykoná. Tomuto útoku se říká SQL injection. Zrovna proti tomuto případu je náš wrapper imunní, jelikož jsou v něm určitá nastavení, která zrovna tento typ injekce nepovolí. Nejedná se však o výchozí nastavení a v žádném případě nezastaví další typy injekcí.

Kdykoli chceme do dotazu vložit nějaký parametr, použijeme otazník a napíšeme ho mimo dotaz! Databáze si tam potom parametr sama a bezpečně dosadí, nikdy to nedělejte za ni. Nikdy nepřerušujte řetězec s SQL dotazem.

Pro jistotu ještě jednou ta samá část kódu tak, jak se správně:

Db::query('
        INSERT INTO uzivatele (jmeno, prijmeni, datum_narozeni)
        VALUES (?, ?, ?)
', $_POST['jmeno'], $_POST['prijmeni'], $datum);

Kód vyzkoušejme. Vložme nějakého uživatele:

Registrace uživatele
localhost
Registrace uživatele
localhost

A podívejme se do databáze, že v ní opravdu je:

Uživatelé v MySQL databázi

Výpis dat

Do našeho jednoduchého skriptu přidejme ještě výpis dat z databáze do HTML tabulky. Tento PHP kód umístíme na konec dosavadního PHP bloku:

$uzivatele = Db::queryAll('
        SELECT *
        FROM uzivatele
');
echo('<h2>Uživatelé</h2><table border="1">');
foreach ($uzivatele as $u)
{
        echo('<tr><td>' . htmlspecialchars($u['jmeno']));
        echo('</td><td>' . htmlspecialchars($u['prijmeni']));
        $datum = date("d.m.Y", strtotime($u['datum_narozeni']));
        echo('</td><td>' . htmlspecialchars($datum));
        echo('</td><td>' . htmlspecialchars($u['pocet_clanku']));
        echo('</td></tr>');
}
echo('</table>');

Nejdůležitější je volání funkce Db::queryAll(). To vykoná databázový dotaz, stejně jako Db::query() a zároveň vrátí všechny řádky, které dotaz vybral. Budeme ji používat při čtení a Db::query() budeme používat při zápisu (přidání, editace, mazání).

Samotný SQL dotaz obsahuje jen 4 slova. Dal by se přeložit jako "Vyber všechny sloupce z uživatelů". Právě hvězdička označuje všechny sloupce. Jelikož neupřesňujeme kteří uživatelé nás zajímají, vybere dotaz všechny řádky z tabulky.

Výsledkem dotazu je pole řádků, které si uložíme do proměnné $uzivatele. Následně pole proiterujeme pomocí foreach cyklu řádek po řádku a pro každý vyechujeme sloupeček do HTML tabulky. Nezapomeneme používat funkci htmlspecialchars(), jinak by si někdo mohl do jména vložit JavaScript a ten by se poté při výpisu jména spustil. Tomuto útoku se říká XSS.

Podívejme se na výsledek aplikace:

Registrace uživatele
localhost

Můžete si zkusit přidávat uživatele, budou se objevovat v tabulce. To by bylo pro dnešní lekci vše. Doufám, že se mi podařilo prolomit ledy a že jste úspěšně vytvořili svou první databázovou aplikaci. V lekci příští, Programujeme neobjektový redakční systém v PHP (NERS), začneme pracovat na slíbeném redakčním systému. Zdrojové kódy dnešní aplikace jsou jako vždy ke stažení v příloze.


 

Stáhnout

Staženo 2881x (3.24 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
47 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Předchozí článek
První databázová tabulka a MySQL ovladače v PHP
Všechny články v sekci
Databáze v PHP pro začátečníky
Miniatura
Následující článek
Programujeme neobjektový redakční systém v PHP (NERS)
Aktivity (4)

 

 

Komentáře
Zobrazit starší komentáře (76)

Avatar
Jiří Čeřovský:17.3.2018 18:11

Ale vyřešilo mě to jen částečně, kdybych například chtěl, aby si uživatel zaškrtal parametry, dle kterých si chce vyfiltrovat výsledek (jako je tomu například v různých e-shopech), tak tento postup nemůžu použít. Co pak s tím?

 
Odpovědět 17.3.2018 18:11
Avatar
Jan Lupčík
Šéfredaktor
Avatar
Odpovídá na Jiří Čeřovský
Jan Lupčík:18.3.2018 17:58

Ahoj,

jde použít to první řešení, co jsem psal. Tedy:

... Budeš si muset vytvořit nějakou rozbalovací nabídku, kam dáš na výběr, podle čeho se to má řadit, a poté budeš zjišťovat, zda-li to uživatel nijak neupravil (ochrana proti MySQL injekci). Poté ten název sloupečku vložíš do dotazu.

Místo rozbalovací nabídky dáš checkboxy a poté budeš mít pole, kde budeš mít povolené hodnoty. Zkontroluješ, jestli uživatel něco neupravil, a vložíš sloupečky do dotazu.

Odpovědět 18.3.2018 17:58
TruckersMP vývojář
Avatar
lafleur.aa
Člen
Avatar
lafleur.aa:4.9.2018 17:35

Zdravím všechny PHP nadšence. Narazil jsem na problém a to takový, že mám databázovou tabulku, která obsahuje ID, TITULEK a OBSAH, který se vypisuje pomocí queryAll do tabulky na web. Mohl by mi někdo poradit, jak vypsat všechna data, ale oddělit jednotlivé skupiny dat například pomocí <hr> ?
Pro lepší představu zde dám příklad, jak by měl výpis vypadat. Předem děkuji za každou radu.

<h2>TITULEK</h2>
<p>OBSAH</p>
<hr>
<h2>TITULEK</h2>
<p>OBSAH</p>

 
Odpovědět 4.9.2018 17:35
Avatar
Tereza -
Člen
Avatar
Tereza -:15.12.2018 14:19

Dokud jsem se řídila návody, vše šlo celkem dobře, jenže pak jsem se pokusila vytvořit jinou databázi a jiný registrační formulář a nastal problém :D

<body>

<h1>Registrace uživatele</h1>

<?php

require_once('Db.php');
Db::connect('127.0.0.1', 'ks_test', 'root', '');
if ($_POST)
{
    $datum = date("Y-m-d H:i:s", strtotime($_POST['datum_narozeni']));
    Db::query('
                                INSERT INTO postavy (jmeno, prijmeni, datum_narozeni, popis, charakteristika, zivotopis)
                                VALUES (?, ?, ?)
                        ', $_POST['jmeno'], $_POST['prijmeni'], $datum, $_POST['popis'], $_POST['charakteristika'], $_POST['zivotopis'] );


    echo('<p>Byl jste úspěšně zaregistrován.</p>');
}
?>

                <form method="post">
                        Jméno:<br />
                        <input type="text" name="jmeno" /><br />
                        Příjmení:<br />
                        <input type="text" name="prijmeni" /><br />
                        Datum narození:<br />
                        <input type="text" name="datum_narozeni" /><br />
                        Popis:<br>
                        <textarea name="popis"></textarea><br>
                        Charakteristika:<br>
                        <textarea name="charakteristika"></textarea><br>
                        Životopis:<br>
                        <textarea name="zivotopis"></textarea><br>
                        <input type="submit" value="Registrovat" /><br>
                </form>

        </body>

Po odeslání formuláře dojde k zobrazení této chyby:
*Registrace uživatele
Warning: PDO::prepare(): SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1 in C:\xampp\htdoc­s\ks_databaze\Db­.php on line 60

Fatal error: Uncaught Error: Call to a member function execute() on boolean in C:\xampp\htdoc­s\ks_databaze\Db­.php:61 Stack trace: #0 C:\xampp\htdoc­s\ks_databaze\Db­.php(71): Db::executeSta­tement(Array) #1 C:\xampp\htdoc­s\ks_databaze\in­dex.php(23): Db::query('\r\n ...', 'Jm\xC3\xA9no', 'P\xC5\x99ijmen\xC3\xAD', '2005-05-11 00:0...', 'Popis', 'Charakteristika', '\xC5\xBDivotopis') #2 {main} thrown in C:\xampp\htdoc­s\ks_databaze\Db­.php on line 61*

Přikládám ještě screen daného úseku z db.php(jde o stejný soubor, co jsem si stáhla, předpokládám, že pro víc sloupců tabulky tam bude potřeba změnit nastavení, ale příliš se v tom nevyznám)

/**
 * Spustí dotaz a vrátí PDO statement
 * @param array $params Pole, kde je prvním prvkem dotaz a dalšími jsou parametry
 * @return \PDOStatement PDO statement
 */
private static function executeStatement($params)
{
        $query = array_shift($params);
        $statement = self::$connection->prepare($query);
        $statement->execute($params);
        return $statement;
}

/**
 * Spustí dotaz a vrátí počet ovlivněných řádků. Dále se předá libovolný počet dalších parametrů.
 * @param string $query Dotaz
 * @return int Počet ovlivněných řádků
 */
 
Odpovědět 15.12.2018 14:19
Avatar
Tereza -
Člen
Avatar
Odpovídá na Tereza -
Tereza -:15.12.2018 14:24

Chybějící otazníky a dokáží rozhodit celý formulář, měla bych si víc dávat pozor na podobné detaily :D

 
Odpovědět 15.12.2018 14:24
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Petr
Člen
Avatar
Petr:7. února 14:50

Ahoj,


return Db::dotazVsechny("
SELECT *
FROM clanky
WHERE titulek LIKE '%".$_POST['se­arch']."%'
");

 
Odpovědět 7. února 14:50
Avatar
Radek Dřímal:25. února 9:55

Nevím zda je to již vyřešeno .:)

Warning: PDO::prepare(): SQLSTATE[21S01]: Insert value list does not match column list: 1136 Column count doesn't match value count at row 1 in C:\xampp\htdoc­s\ks_databaze\Db­.php on line 60

znamená že máš na vstupu méně ? (proměnných) než chceš dosadit hodnot. Počet ? musí být roven počtu vkládaných údajů (proměnných)

VALUES (?, ?, ?, ?, ?, ?) asi tak :)

 
Odpovědět 25. února 9:55
Avatar
Jiří Hruška:11. května 11:44

Ahoj, potřeboval bych zjístit jak mohu vypsat do <select><option> // vypsat všechny registrované. Lze to udělat nějak jednoduše? Díky

 
Odpovědět 11. května 11:44
Avatar
Jaroslav Smrž
Redaktor
Avatar
Jaroslav Smrž:11. května 11:52

Ahoj, pokud používáš místní DB wrapper, tak kód by mohl vypadat následovně:

<select name="kategorie" class="form-control">
        <?php
        $dropdown = DB::QueryAll('SELECT kat_nazev FROM kategorie');
                foreach ($dropdown as $drop){
                        echo('<option>');
                        echo(htmlspecialchars($drop['kat_nazev']));
                        echo('</option>');
                }
        ?>
</select>
Odpovědět 11. května 11:52
I have no idea what it is doing but I´m scared to delete it... xD
Avatar
Stivko
Člen
Avatar
Stivko:14. června 20:06

Super návod :) Zatím perfektně chápu.

Odpovědět 14. června 20:06
Nikdy není pozdě začít s něčím novým
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 86. Zobrazit vše