Letní akce! Lákají tě IT školení C#, Javy a PHP v Brně? Přihlas se a napiš nám do zpráv kód "BRNO 500" pro slevu 500 Kč na libovolný brněnský kurz. Lze kombinovat se slevami uvedenými u školení i použít pro více kurzů. Akce končí 28.7.

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

PHP Databáze pro začátečníky Formulář a výpis dat z databáze do tabulky v PHP American English version English version

Unicorn College ONEbit hosting 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 . '")');

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 2497x (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?
45 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.
Aktivity (4)

 

 

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

Avatar
Petra D.
Člen
Avatar
Petra D. :9. února 9:16

Může mi někdo poradit? Když zadám do formuláře jakékoliv datum před rokem 1900 tak se automaticky vyplní 1.1.1970, jde to nějak změnit? Předpokládám, že problém je někde při převodu data na správný formát? U žijících lidí je to v pohodě, ale pokud bych chtěla databázi použít pro genealogii tak je nepoužitelná... díky

Odpovědět 9. února 9:16
Jaký si to uděláš, takový to máš...
Avatar
Odpovídá na Petra D.
Martin Bušek:10. února 20:17

Ahoj, napadlo mě jen tohle

date_format(date_create('1234-01-01'), 'M-d-Y');
 
Odpovědět 10. února 20:17
Avatar
Petr Polášek:18. února 8:34

Ahoj, mám dotaz ohledně tohoto

        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>');
}

Konkrétně $datum. Proč to musím znovu upravovat, když už jsem ho přece jednou do tohoto tvaru dal?

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>');
                }

Předpokládám, že to je kvůli převedení na náš formát datumu a kvůli tohoto H:i:s?

Editováno 18. února 8:35
 
Odpovědět 18. února 8:34
Avatar
IT Man
Redaktor
Avatar
Odpovídá na Petr Polášek
IT Man:18. února 9:18

V tom prvním to vypisuješ, tedy dáváš to do tvaru 18.02.2018. V tom druhém to ukládáš do databáze a ta to nepřelouská jinak než 2018-02-18 09:18:35.

Odpovědět  +1 18. února 9:18
Cokoliv a kdokoliv může jednou uspět.
Avatar
Jiří Čeřovský:17. března 14:03

Ahoj,

krásný článek. Jednoduše napsaný, ale zároveň je v něm plno informací. Vše jsem zvládl, ale mám jeden dotaz. Chtěl bych na stránce nechat zadat uživatele, podle kterého kritéria se má databáze seřadit, ale nemůžu přijít na to, jak to udělat. Pravděpodobně bude kámen úrazu v použití Db:queryAll a Db:query. Jedno je pro čtení a druhé pro zápis. Kód mám následující:

<form method="post" action="kina.php">
Seřadit dle:<input type="radio" name="seradit" value="vek" checked="checked">

<input type="submit" value="Odeslat" />
</form>
<?php
require_once('Db­.php');
Db::connect('127­.0.0.1', 'kyvadloorg', 'root', '');
if ($_POST)
{

echo($_POST['se­radit']);
$kina = Db::queryAll('
SELECT *
FROM uzivatele
ORDER BY ?
', $_POST['seradit']);

Při použit tohoto kódu mi se mi nic neseřadí. Můžete mi, prosím Vás, někdo pomoci?

Děkuju

 
Odpovědět 17. března 14:03
Avatar
Odpovídá na Jiří Čeřovský
Dominik Gavrecký:17. března 14:16

Ak si dumpneš to query čo ti to vráti ?

Odpovědět 17. března 14:16
Hlupák nie je ten kto niečo nevie, hlupákom sa stávaš v momente keď sa na to bojíš opýtať.
Avatar
IT Man
Redaktor
Avatar
Odpovídá na Jiří Čeřovský
IT Man:17. března 14:21

Ahoj,

nechci hned nějak buzerovat, ale příště pro vložení kódu použij tag [ code ] (bez mezer), abychom se v tvém kódu mohli lépe orientovat. Děkuji. :)

Hlavní kámen úrazu je to, že otazníky se dají použít pouze pro hodnoty, ne pro názvy sloupečků. Tvé seřazení tedy nebude fungovat. 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.
Druhá možnost (a i ta lepší) je vytvořit si opět rozbalovací nabídku, kam dáš opět na výběr, podle čeho se mají ty položky řadit. Ty položky v seznamu budou mít nějakou hodnotu; nějaké ID. Podle toho ID budeš v kódu zjišťovat, o co jde, a podle něj spustíš vybraný dotaz, takže nikam nebudeš nic dosazovat. ;)

Snad ti má odpověď pomohla. :)

Odpovědět 17. března 14:21
Cokoliv a kdokoliv může jednou uspět.
Avatar
Odpovídá na IT Man
Jiří Čeřovský:17. března 17:55

Skvělé, to mě nenapadlo. Jak jednoduché :)

 
Odpovědět 17. března 17:55
Avatar
Odpovídá na IT Man
Jiří Čeřovský:17. března 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. března 18:11
Avatar
IT Man
Redaktor
Avatar
Odpovídá na Jiří Čeřovský
IT Man:18. března 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. března 17:58
Cokoliv a kdokoliv může jednou uspět.
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 78. Zobrazit vše