Avatar
pgarsky
Člen
Avatar
pgarsky:

Ahoj, mám takový problém. Chtěl bych na své stránce možnost změnit si heslo, avšak ve scriptu se vyskytla chyba.
Chyba:

Warning: PDOStatement::e­xecute(): SQLSTATE[HY000]: General error: 2031 in C:\Users\Pavel\Des­ktopyprojekt\\u­cet\Db.php on line 61
Používám wrapper tady z itnetwork sekce PHP tutoriálů NERS.
Můj vymyšlený kód je takovýto:
HTML:

<form method="post">
               <h2>Změna hesla: </h2>
               <p>Staré heslo: </p>
               <input name="stare_heslo" type="password">
               <p>Nové heslo: </p>
               <input name="nove_heslo" type="password">
               <p>Nové heslo znovu: </p>
               <input name="nove_heslo_znovu" type="password"><br />
               <input type="submit" value="Změnit">
           </form>

PHP:

if ($_POST)
{
    if ($_POST['stare_heslo'] = Db::query('SELECT id FROM uzivatele WHERE jmeno=?') && $_POST['nove_heslo'] = $_POST['nove_heslo_znovu'])
    {
        Db::query('
        UPDATE SHA1(heslo)
        FROM uzivatele
        WHERE id=?
        ', $_POST['nove_heslo'] . "123456789");
        echo('<p style="text-align: center; font-size: 25px;">Heslo bylo úspašně změněno.</p>');
    }
    else
        echo('<p style="text-align: center; font-size: 25px;">Heslo se nepodařilo změnit, zkuste to znovu.</p>');
}

Pomůžete mi tuto chybu opravit?

 
Odpovědět 2. září 23:00
Avatar
pgarsky
Člen
Avatar
pgarsky:

Pokud možno, ještě vysvětlit chybu v mém kódu.

 
Nahoru Odpovědět 2. září 23:03
Avatar
Odpovídá na pgarsky
Josef Kuchař (Pepa489):

U řádku na kterém je

Db::query('SELECT id FROM uzivatele WHERE jmeno=?')

nedosazuješ za otazník hodnotu. ;)

Nahoru Odpovědět 2. září 23:17
2x piš, jednou debuguj
Avatar
Oxtimus
Člen
Avatar
Oxtimus:

Podle mě je tam chyb hned několik:

1:

Db::query('SELECT id FROM uzivatele WHERE jmeno=?') // Chybí parametr, který se dosadí za otazník

Db::query('SELECT id FROM uzivatele WHERE jmeno=?', [$jmeno]) // Takto by mohla vypadat oprava

2:

$_POST['nove_heslo'] = $_POST['nove_heslo_znovu'] // Pokud se ptáš na shodu, je nutné použít dvě nebo tři rovnítka

$_POST['nove_heslo'] === $_POST['nove_heslo_znovu'] // Takto by mohla vypadat oprava

3:

Db::query('
        UPDATE SHA1(heslo)
        FROM uzivatele
        WHERE id=?
        ', $_POST['nove_heslo'] . "123456789"); // Nejsem si jist, ale myslím, že ve wrapperu z této sítě je nutno dávat parametry do pole

Db::query('
        UPDATE SHA1(heslo)
        FROM uzivatele
        WHERE id=?
        ', [$_POST['nove_heslo'] . "123456789"]); // Takto by mohla vypadat oprava
Editováno 2. září 23:20
Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
 
Nahoru Odpovědět  +3 2. září 23:18
Avatar
00
Člen
Avatar
00:
UPDATE xxx SET xxx

a ne

UPDATE xxx FROM xxx
 
Nahoru Odpovědět  +1 3. září 11:09
Avatar
Odpovídá na pgarsky
Martin Štěpánek (Enormyk):
if ($_POST['stare_heslo'] = Db::query('SELECT id FROM uzivatele WHERE jmeno=?')

ještě kontroluješ jestli se staré heslo rovná id uživatele ;-)

Nahoru Odpovědět 3. září 11:33
Nesnáším, když někdo u if nepoužívá {}, byť se jedná o jeden řádek.
Avatar
pgarsky
Člen
Avatar
Odpovídá na Martin Štěpánek (Enormyk)
pgarsky:

To je podlě mě blbost, staré heslo se nemůže rovnat id, protože pak by to bylo třeba 123456 = 1. Ne ?

 
Nahoru Odpovědět  -1 3. září 11:54
Avatar
Odpovídá na pgarsky
Martin Konečný (pavelco1998):

jo, ale takhle to tam máš ty :D
když s tím v podstatě začínáš, tak to dělej pomalu a sleduj, jaká metoda má jaké návratové hodnoty. Sice neznám místní DB wrapper, ale je mi jasný, že metoda Db::query() ti nebude vracet jeden konkrétní výsledek jednoho sloupce.
Ty potřebuješ zjistit, jestli se staré heslo shoduje s tím v databázi. K tomu máš dvě možnosti:

  1. vytáhnout si heslo z DB podle uživatele. To pak porovnáš v PHP s heslem zadaným ve formuláři To hledej podle jeho ID, ne podle jména - máš zaručený, že díky PK (primární klíč) to ID bude vždycky unikátní a navíc se podle něj hledá rychleji.
  2. poslat dotaz do DB, kde do WHERE zadáš ID uživatele a heslo. Pokud se vrátí jeden záznam, tak se heslo shoduje. Pokud se vrátí nula záznamů, heslo bylo zadaný špatně. Tenhle způsob ale v podstatě nebudeš moct použít, pokud hashuješ způsobem, který DB neumí. Být tebou bych proto zvolil možnost a).

A mimo to, rovnítko v PHP můžeš použít na tři způsoby

$a = 10;  // přiřazení hodnoty, tady bude výsledek vždycky TRUE! tohle když použiješ v podmínce, tak ti vždycky projde

$a == 10;  // porovná proměnnou s číslem 10, při tom nezáleží na datovém typu ($a může být 10 jako číslo i 10 jako řetězec)

$a === 10;  // porovná proměnnou s číslem deset a zároven udělá shodu datových typů. Pokud $a bude řetězec  ($a = "10"), tak výsledek bude FALSE
 
Nahoru Odpovědět  +2 3. září 12:09
Avatar
00
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
00:
($a = FALSE) == FALSE
// ALE
($a = TRUE) == TRUE
// !!!
 
Nahoru Odpovědět 3. září 12:42
Avatar
Odpovídá na 00
Martin Konečný (pavelco1998):

zajímavé, beru zpět. Nicméně házet do podmínky jedno rovnítko je sebevražda sama o sobě

 
Nahoru Odpovědět  +2 3. září 12:55
Avatar
pgarsky
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
pgarsky:

takže jak by podle tebe měl vypadat kód ?

 
Nahoru Odpovědět 3. září 13:08
Avatar
Odpovídá na pgarsky
Martin Konečný (pavelco1998):

Neznám ten DB wrapper, ale asi něco takovýho

$vysledek = DB::query("
        SELECT heslo
        FROM uzivatel
        WHERE id = ?
", array($_SESSION["uzivatel_id"]));

$data = $vysledek->fetch();
$stareHeslo = nejakaHashFunkce($_POST["stare_heslo"]);
if ($stareHeslo === $data["heslo"]) {
        // OK
}
Editováno 3. září 13:40
 
Nahoru Odpovědět  +1 3. září 13:40
Avatar
00
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
00:

Přiřazování vrací přiřazovanou hodnotu :-)

 
Nahoru Odpovědět  +2 3. září 19:19
Avatar
Odpovídá na 00
Martin Konečný (pavelco1998):

A to jsem myslel, že to vrací výsledek "operace". Nicméně se to do podmínky přetypuje na bool, což ve většině případů znamená TRUE a začátečník na tom hezky narazí, pokud nebude přesně vědět, co dělá :D
Každopádně díky za upozornění

 
Nahoru Odpovědět 3. září 20:16
Avatar
Odpovídá na pgarsky
Martin Konečný (pavelco1998):

To je hezký, ale takhle ti nemá kdo jak poradit. Co zkusit třeba napsat, proč to nefunguje (chybové hlášení, co to má dělat a co to dělá, ...)? Jinak jsem psal, že ten DB wrapper neznám, jen jsem ti nastínil, jak by to mohlo vypadat.

 
Nahoru Odpovědět  +1 3. září 20:30
Avatar
50P
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
50P:

Já si ještě našel na w3shools.com postupy, jakými to dělat bez tohoto wrapperu.

 
Nahoru Odpovědět 5. září 17:27
Avatar
Odpovídá na 50P
Martin Konečný (pavelco1998):

díky za informaci :D Pokud používáš PDO, je to OK. Já používám primárně Doctrine 2, případně Nette\Database (pokud fakt musim a neni jiná možnost), s ničím jiným zkušenosti nemám

 
Nahoru Odpovědět 5. září 17:41
Avatar
50P
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
50P:

No já používám zatím jen mysqli, ale k PDO se taky dostanu. Jinak teď používám databáze na Virt. PC s Linuxem.

 
Nahoru Odpovědět 5. září 17:58
Avatar
Odpovídá na 50P
Martin Konečný (pavelco1998):

mysqli je skoro to samý co PDO. Doporučuji PDO

 
Nahoru Odpovědět  +1 5. září 18:10
Avatar
Petr Linhart
Člen
Avatar
Odpovídá na pgarsky
Petr Linhart:

Princip je asi takový, že při předání hodnot z formuláře se ověří shodnost otisku zadaného starého hesla s otiskem uloženým v databázi u konkrétního uživatele (přihlášeného) a shodnost obou zadání nového hesla. Pokud podmínka projde dojde k aktualizaci uloženého otisku hesla v databázi otiskem nového hesla.
Kód si musíš přizpůsobit svým potřebám, nastavením a dalším věcem.

if ($_POST)
{
    if (sha1($_POST['stare_heslo']) == Db::query('SELECT heslo FROM uzivatele WHERE id=?', $_SESSION['uzivatel_id'] && $_POST['nove_heslo'] == $_POST['nove_heslo_znovu'])
    {
        Db::query('
        UPDATE uzivatele
        SET heslo=sha1(?)
        WHERE id=?
        ', $_POST['nove_heslo'], $_SESSION['uzivatel_id']);
        echo('<p style="text-align: center; font-size: 25px;">Heslo bylo úspěšně změněno.</p>');
    }
    else
        echo('<p style="text-align: center; font-size: 25px;">Heslo se nepodařilo změnit, zkuste to znovu.</p>');
}
 
Nahoru Odpovědět 9. září 0:23
Avatar
IT Man
Redaktor
Avatar
Odpovídá na Petr Linhart
IT Man:

Jenom takové dvě menší poznámky. :)

  1. Z hlediska pohodlnosti pro uživatele bych doporučoval mít dvě podmínky. Nejdřív ověřit staré heslo a dát mu zprávu o tom, že je špatně a pak ověřovat, zda opakování nového hesla je správně a dát mu o tom zprávu.
  2. V místní třídě s databází se musí ty parametry pro dotaz předávat v poli.
Editováno 9. září 6:41
Nahoru Odpovědět 9. září 6:40
Když nevíš jak dál, podá ti ruku někdo, od koho by jsi to nečekal. A tu šanci musíš přijmout!
Avatar
pgarsky
Člen
Avatar
Odpovídá na IT Man
pgarsky:

No, já zatím neumím odesílat maily s těmahle informace. Tak se tě rovnou ptám, jak na to a taky bych potřeboval vědět, jak v emailu odřádkovat nový řádek.

 
Nahoru Odpovědět 9. září 14:10
Avatar
Petr Linhart
Člen
Avatar
Odpovídá na IT Man
Petr Linhart:

1. vycházel sem z původního kódu tazatele, abych mu nastínil způsob jakým má nad tím uvažovat, nicméně:

if ($_POST)
{
    if (sha1($_POST['stare_heslo']) == Db::query('SELECT heslo FROM uzivatele WHERE id=?', $_SESSION['uzivatel_id'])
    {
                if($_POST['nove_heslo'] == $_POST['nove_heslo_znovu'])
                {
                        Db::query('UPDATE uzivatele SET heslo = sha1(?) WHERE id = ?', $_POST['nove_heslo'], $_SESSION['uzivatel_id']);
                        $zprava = 'Heslo bylo úspěšně změněno.';
                }
                else{$zprava = 'Zadání nového hesla se neshodují.';}
    }
        else {$zprava = 'Špatně zadané původní heslo.';}
}
if (isset($zprava)){echo('<p>' . $zprava . '</p>');}

2. vycházím opět z původního kódu v tutorialu, nějak víc sem nezkoumal ani wrapper ani nic dalšího. Případná oprava je už jen drobnost.

Editováno 9. září 15:59
 
Nahoru Odpovědět 9. září 15:58
Avatar
Petr Linhart
Člen
Avatar
Odpovídá na pgarsky
Petr Linhart:

Maily obsahující heslo ani neposílej.

Odřádkování v mailu provedeš podle toho v jakém typu (dáno hlavičkou content-type) to odesíláš.
Pokud posíláš jako prostý text (content-type: text/plain) tak odřádkuješ pomocí

\n

, pokud to posíláš jako formátovaný html (content-type: text/html) tak musíš používat tag

<br>
 
Nahoru Odpovědět 9. září 16:18
Avatar
pgarsky
Člen
Avatar
Odpovídá na Petr Linhart
pgarsky:

No jo, ale jak to heslo potom říct tomu uživateli ?

 
Nahoru Odpovědět 9. září 21:10
Avatar
Jiří Gracík
Redaktor
Avatar
Odpovídá na pgarsky
Jiří Gracík:

Ten uživatel to heslo napíše. Tak nějak se předpokládá, že uživatel ví, co za heslo napsal.

Nahoru Odpovědět  +2 9. září 22:56
Creating websites is awesome till you see the result in another browser ...
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 28 zpráv z 28.