Autor Zpráva
Arpagone
Profil
Dobrý den,
omlouvám se. Stále jsem v PHP začátečník.

Rád bych pracoval při vkládání dat do tabulek v databázi MYSQL tak že, vybraná databázová tabulka se bude vybírat podle názvu tabulky uložené v proměnné. Bohužel příkaz INSERT INTO $nazevproměné nefunguje.
Paradoxně u příkazů UPDATE nebo SELECT to problém není. Dokázal by mi prosím někdo poradit řešení?
Kajman
Profil
Ukažte kód.
Arpagone
Profil
Db::query('
INSERT INTO $promenna (cislo, typ_poznamky, nadpis, text, datum_pripadu, datum_vlozeni, datumacas )
VALUES (?,?,?,?,?,?,?)
',htmlspecialchars ($_POST['cislo']), $_POST['typ_poznamky'], $_POST['nadpis'], $_POST['text'], $_POST['datum_pripadu'], $datum, $datumacas );


Pokud $promenna nahradím skutečným názvem databázové tabulky, tak vše funguje dobře. Jinde chyba nebude.
anonym_
Profil *
Arpagone:
Ja tam vidím syntax error.

Druha věc je, ze takhle se zo neřeší. Název tabulky znáš, jinak bys nevěděl ani, s jakými sloupci pracovat. Trochu mi to přijde, jako by každy napr. zákazník mel svoji vlastní tabulku, coz je samozrejme spatny navrh databaze.

Posledni dva sloupce mi přijdou duplicitni, pokud obsahují oba dva datum vložení záznamu.


Pardon, tak nevidím, prekoukl jsem se na telefonu.

Zato tam vidím nesprávně ošetřené proměnné (htmlspecialchars určitě neni vhodné ošetření ani pro vstup do databaze, ani pro cislo).
Firibix
Profil
Reakce na Arpagone:
V řetězci uzavřeném do jednoduchých uvozovek neprobíhá nahrazování proměnných, musíš je nahradit dvojitými uvozovkami.

$promenna = 'tabulka';

echo 'INSERT INTO $promenna';
// vypíše INSERT INTO $promenna

echo "INSERT INTO $promenna";
// vypíše INSERT INTO tabulka
Arpagone
Profil
Firibix:
Super!!!!! To je přesně ono! Moc děkuji. Funguje to.


anonym:
Také děkuji. Je pravda že každý uživatel má svoji tabulku, která je kromě názvu stejná s ostatními uživateli. Vím že by se to dalo dát do jedné tabulky a přidat sloupec s identifikací uživatele. Přijde mi to ale takto bezpečnější a rychlejší. Možná se mýlím.
Ošetření vstupu do databáze pomocí htmlspecialchars jsem někde četl jako doporučeníhodné.
Firibix
Profil
Reakce na Arpagone:
Je pravda že každý uživatel má svoji tabulku, která je kromě názvu stejná s ostatními uživateli. Vím že by se to dalo dát do jedné tabulky a přidat sloupec s identifikací uživatele. Přijde mi to ale takto bezpečnější a rychlejší. Možná se mýlím.
To je určitě špatně. Navíc předpokládám, že $promenna je ve skutečnosti něco jako $_POST['uzivatel'], tedy to není hodnota z nějakého předem daného bezpečného seznamu. V takovém případě je moje rada nedostatečná, jelikož takový SQL dotaz je zranitelný na SQL injection. $promenna se musí ošetřit escapováním, podívej se do dokumentace knihovny, kterou pro komunikaci s databází používáš, a najdi správnou funkci.

$promenna = '…'; // počáteční nastavení

$promenna = escapuj($promenna); // ošetření
Db::query("INSERT INTO `$promenna` …"); // navíc zpětné apostrofy okolo `$promenna`

Ošetření vstupu do databáze pomocí htmlspecialchars jsem někde četl jako doporučeníhodné.
Je důležité pochopit, že ošetření vstupu záleží na kontextu, ve kterém se pohybuješ, neexistuje žádná univerzální funkce.

htmlspecialchars ošetřuje v kontextu HTML tak, aby když uživatel zadá <p>, se na stránce objevilo <p>, a ne aby se udělal nový odstavec. Správné místo, kde htmlspecialchars použít, je až při výpisu dat od uživatele do stránky (tedy u funkce echo, případně v nějakém šablonovacím systému).

Ošetření vstupu do databáze znamená, že chceme zabránit tomu, aby uživatel na databázi poslal řídící příkazy typu DROP TABLE. To umí ošetřit např. funkce mysqli_real_escape_string, ale obvykle použiješ funkci, kterou nabízí tvoje knihovna, která se o komunikaci s databází stará. U databází je to oproti třeba HTML ještě trochu jiné, protože nabízejí tzv. prepared statements, kdy se nejprve pošle SQL dotaz bez dat (místo nich jsou otazníky) a až potom se pošlou data. V tom okamžiku je naprosto jasné, co jsou data a co řídící příkazy, a není třeba vstup explicitně ošetřovat (prepared statements jsou ošetřením dat samy o sobě). Všimni si, že to používáš už teď (mimochodem, název tabulky se otazníkem nahradit nedá, takže ten budeš muset opravdu ošetřit ručně, jak jsem psal výše).
Arpagone
Profil
Děkuji za další radu.
Proměnná uživatele je získána pro toto použití tak, že uživatel má svoje přihlašovací sessions a pomocí něho se vybírá z databáze uživatelů i jméno uživatele. (snad jsem se vyjádřil dobře). Tj uživatel sám nemůže tuto proměnnou zadat ale je přiřazena podle jeho přihlašovacích údajů.
Uživatel, který nezná přistupové heslo do této "aplikace", by se tedy neměl vůbec k žádnému zadávání do databáze dostat.
Jak píšu, jsem začátečník a samouk. Bohužel o knihovnách zatím nic nevím.
anonym_
Profil *
Arpagone:
Jak píšu, jsem začátečník a samouk
Ten postup se samostatnou tabulkou pro každého uživatele nemohl být ani v tom nejhloupějším tutoriálu nebo knize, podle které/ho ses učil.

Doporučuji to zavčasu předělat tak, abys měl jednu tabulku s přidaným sloupcem id_uzivatele. Do budoucna ti to ušetří mnoho práce a starostí. Pokud jsi stále v začátcích, jakože jsi, doporučuji ke studiu přibrat nějakou knihu nebo tutoriál a učit se s jeho pomocí.
Firibix
Profil
Reakce na Arpagone:
Proměnná uživatele je získána pro toto použití tak, že uživatel má svoje přihlašovací sessions a pomocí něho se vybírá z databáze uživatelů i jméno uživatele. (snad jsem se vyjádřil dobře). Tj uživatel sám nemůže tuto proměnnou zadat ale je přiřazena podle jeho přihlašovacích údajů.
A do databáze zadává jméno uživatele kdo? Klasická výmluva je, že registraci uživatel neprovádí sám, ale jenom nějaká důvěryhodná osoba. I tak je to ale časovaná bomba, která čeká, až daná osoba zapomene, že do políčka nesmí napsat uvozovku.

Neescapování vstupních dat by se dalo odpustit maximálně v případě, že jsou hodnoty natvrdo uvedené ve zdrojovém kódu, jsou přímo určené k použití v SQL dotazu, je u nich řádný komentář, že se bez ošetření posílají do databáze a programátor sám zajistí, že nezpůsobí chybu.

Bohužel o knihovnách zatím nic nevím.
Zjevně nějakou používáš, když voláš Db::query. Třída Db by ideálně měla poskytovat i nějakou escapovací funkci, kterou použiješ místo escapuj v kódu z [#7].
Keeehi
Profil
Arpagone:
Tj uživatel sám nemůže tuto proměnnou zadat ale je přiřazena podle jeho přihlašovacích údajů.
Tenhle předpoklad bude fungovat do chvíle než se ti zaregistruje uživatel se jménem ' UNION ALL SELECT * FROM users --
Samozřejmě tohle přesně fungovat nebude, ale pro ukázku možného útoku to stačí.
Arpagone
Profil
anonym:
Jsme jen dva uživatelé.


Keeehi:
Registrovat se nikdo nemůže sám. Registruji nového uživatele jen já jako administrátor. Není to pro široké využití. Zatím s tím pracujeme dva a ani v budoucnu nebude více než 3-5 uživatelů.
Přesto se učím, tak je dobře to zlepšovat jako by to bylo určené pro veřejnost. Navíc omylem může udělat chybu i někdo z nás.


Firibix:
Nevěděl jsem že jde o knihovu. Použil jsem wraper, který poskytl k volnému použití itnetwork.cz . Určitě si vezmu všechny rady k srdci a postupně budu zabezpečovat lépe a lépe.


anonym:
Jak jsem psal, jsem samouk a nakoupil jsem knihy a koukám na tutoriály. Ne vše ale dokážu hned pochopit. Prostě se prokousávám postupně.


anonym:
Těch tabulek ja samozřejmě mnohem více, protože tahám hodně dat z externích zdrojů a ostatní tabulky jsou využívány společně. Bohužel jde i často o dosti velké soubory, které se navíc musí aktualizovat a přitom potřebujeme i stará data. To samozřejmě i zpomaluje databázi. Škoda že v phpMyadmin od Wedosu nemohu tabulky třídit do adresářů.
Firibix
Profil
Reakce na Arpagone:
Škoda že v phpMyadmin od Wedosu nemohu tabulky třídit do adresářů.
No, škoda… MySQL je relační databáze, ne souborový systém. Myslím, že nějaké „adresáře“ v phpMyAdminu by zbytečně podporovaly začátečníky ve špatném návrhu databáze.

Bohužel jde i často o dosti velké soubory, které se navíc musí aktualizovat a přitom potřebujeme i stará data. To samozřejmě i zpomaluje databázi.
Snad v databázi nemáš i tabulky typu faktury_2019, faktury_2020 a podobně. Pomalou databázi v drtivé většině případů způsobuje její špatný návrh (datové typy, indexy, nenormální forma), neefektivně napsané SQL dotazy nebo neefektivní zpracování v PHP, nikoliv velký počet dat (mluvím o milionech řádků).
Arpagone
Profil
Jednotlivé tabulky mají stovky tisíc řádků.
blaaablaaa
Profil
Arpagone:
Stovky tisíc či miliony řádků nejsou pro (správně navrženou) db problém. Rozhodně je (většinou) špatně vytvářet tabulky podle uživatele, roku apod.
Kcko
Profil
blaaablaaa:
Někdy ano ;-)
blaaablaaa
Profil
Kcko:
Tohle je zrovna imho pripad, ktery se vyplati predpocitat. Ale bezne tohle vyvojar resit nemusi.
Kajman
Profil
Kcko:
Ale kdybys měl pro každého uživatele vlastní tabulku, tak to bude ještě pomalejší a dotaz na statistiku všeho ani nesestavíš.
Kcko
Profil
Kajman:
Ale já přece nic takového netvrdím, nikdy v životě by mě nenapadlo dělat tabulky dle roků / uživatelů a obecně hodnot, co se vlastně ukládájí do řádků.
Ale v určitých případech jsem si ukládal redundatní data, ke kterým bych se mohl přes několik JOINů dostat (resp to byly FK). A to z toho důvodu, aby dotazy byly co nejrychlejší a dotaz nebyl na A4-ku.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0