Autor Zpráva
marek187
Profil
Všade na internete nachádzam komplikované alebo zbytočne zložité spôsoby ako overiť existenciu zápisu v tabuľke, ja však využívam takýto jednoduchý spôsob:

$username = $_POST['username'];
$user = $DB->row("SELECT username FROM users WHERE username='$username'");

if (!$user) { 
  // vytvorenie nového užívateľa
}

Tento spôsob funguje ako by mal, je však správny/valídny?
juriad
Profil
marek187:
Jelikož nevíme, co metoda row dělá, můžeme jen hádat, že vrátí jako asocitaivní pole první řádek výsledku dotazu, nebo FALSE či NULL pokud žádný řádek není vrácen.
Je možné, že tobě se ten tvůj kód líbí právě z důvodu použití té knihovny, která ti trochu zkrátí kód.

Ten dotaz obsahuje spoustu chyb:
1) SQL Injection. Nikdy nevkládej řetězec ze vstupu (od uživatele) přímo do dotazu. Co se stane, pokud bude chtít uživatel uživatelské jméno s apostrofem. Dotaz selže a aplikace ti padne na hubu. Jak tento problém vyřešit nevím, protože neznám knihovnu, kterou používáš k pokládání dotazů.

2) Zbytečně taháš zpět data, která již znáš; lepší by bylo: SELECT 1 FROM users WHERE. Ale toto je jen detail. Obvykle bývá problém s tím, že pro zjištění počtu řádků se zbytečně položí dotaz SELECT * FROM ... místo SELECT COUNT(*) FROM ...

3) Smysl tohoto dotazu. Pokud ho chceš jako kontrolu před vložením uživatele, tak toto nestačí. Představ si, že tvůj server je hodně zatížený a registrují se stovky uživatelů za sekundu. Pak se může stát, že se budou registrovat dva lidé se stejným jménem. A nikdo negarantuje, že se kontrola a vložení do databáze provede bez přerušení. Mějme dva lidi l1 a l2, kteří se chtějí registrovat se jménem u.
Pak očekáváš, že proběhnou následující dotazy do databáze:
l1: SELECT -> nevrátí nic -> OK
l1: INSERT -> OK
l2: SELECT -> vrátí jeden řádek -> ukončíme registraci
Ale ono se může stát i toto:
l1: SELECT -> nevrátí nic -> OK
l2: SELECT -> nevrátí nic -> OK
l1: INSERT -> OK
l2: INSERT -> ???? tady záleží zda je nad sloupcem username unikátní klíč; je-li pak dojde k chybě dotazu, není-li pak se vloží duplicitní záznam.

Kontrola, kterou provádíš má tedy jen informační charakter, můžeš to použít jako nápovědu pro uživatele, že již takové jméno existuje. Ale neměl bys na to spoléhat. Správné řešení je mít unikátní klíč nad sloupcem username a neprovádět kontrolu SELECTem, ale provést rovnou INSERT a očekávat, že může selhat. Pokud selže zkontrolovat příčinu selhání (viz). Pokud je přičinou unikátní klíč, tak nahlaš uživateli, že takové jméno již existuje. Pokud nedojde k chybě, tak se uživatel úspěšně registroval.
marek187
Profil
juriad:
Jelikož nevíme, co metoda row dělá, můžeme jen hádat, že vrátí jako asocitaivní pole první řádek výsledku dotazu, nebo FALSE či NULL pokud žádný řádek není vrácen.
Je možné, že tobě se ten tvůj kód líbí právě z důvodu použití té knihovny, která ti trochu zkrátí kód.


    public function row($query) {
        $this->query($query);
        if (mysql_num_rows($this->result) != 0) {
            return mysql_fetch_object($this->result);
        } else {
            return null;
        }

1) SQL Injection. Nikdy nevkládej řetězec ze vstupu (od uživatele) přímo do dotazu. Co se stane, pokud bude chtít uživatel uživatelské jméno s apostrofem. Dotaz selže a aplikace ti padne na hubu. Jak tento problém vyřešit nevím, protože neznám knihovnu, kterou používáš k pokládání dotazů.

$username = $_POST['username']; som dal len ako príklad, na stránke to mám ošetrené...

2) Zbytečně taháš zpět data, která již znáš; lepší by bylo: SELECT 1 FROM users WHERE. Ale toto je jen detail. Obvykle bývá problém s tím, že pro zjištění počtu řádků se zbytečně položí dotaz SELECT * FROM ... místo SELECT COUNT(*) FROM ...

Takže najpraktickejšie z tých troch je toto? SELECT 1 FROM users WHERE

3) Smysl tohoto dotazu. Pokud ho chceš jako kontrolu před vložením uživatele, tak toto nestačí. Představ si, že tvůj server je hodně zatížený a registrují se stovky uživatelů za sekundu. Pak se může stát, že se budou registrovat dva lidé se stejným jménem. A nikdo negarantuje, že se kontrola a vložení do databáze provede bez přerušení.

Kontrola, kterou provádíš má tedy jen informační charakter, můžeš to použít jako nápovědu pro uživatele, že již takové jméno existuje. Ale neměl bys na to spoléhat. Správné řešení je mít unikátní klíč nad sloupcem username a neprovádět kontrolu SELECTem, ale provést rovnou INSERT a očekávat, že může selhat. Pokud selže zkontrolovat příčinu selhání (viz). Pokud je přičinou unikátní klíč, tak nahlaš uživateli, že takové jméno již existuje. Pokud nedojde k chybě, tak se uživatel úspěšně registroval.


A úplne najpraktickejšie je SELECT použíť pre informovanie užívateľa, či je obsadené (overenie dostupnosti) a pre istotu na ochranu duplicitných záznamov použiť ešte dodatočne tento unikátny kľúč?

ALTER TABLE users ADD UNIQUE (username)

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: