PHP - změna hesla - nefukční změna / login – PHP – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

PHP - změna hesla - nefukční změna / login – PHP – Fórum – Programujte.comPHP - změna hesla - nefukční změna / login – PHP – Fórum – Programujte.com

 

David
~ Anonymní uživatel
177 příspěvků
30. 6. 2017   #1
-
0
-

Ahoj,

prosím o radu, nevíte proč se mi po změně hesla nedaří přihlásit pod novým heslem ? 

Samozřejmě nejde ani to nové heslo zadat a změnit, musim dávat stále to první.

changepassword.php

<?php 
        $formValid = new Security;

        if(isset($_POST['changepass'])) {
            $username = $_SESSION['username'];
            $oldPassword = $formValid->validForm($_POST['oldpassword']);
            $newPassword = $formValid->validForm($_POST['newpassword']);
            $confirmPassword = $formValid->validForm($_POST['confirmnewpassword']);
            $checkPassword = User::passwordVerify($username,$oldPassword);
            if($checkPassword) {
                if($confirmPassword == $newPassword) {
                    $changePassword = User::changePassword($username,$oldPassword,$newPassword);
                    if($changePassword) {
                        echo "<br /><center>Změna hesla proběhla úspěšně</center><br />";
                    } 
                } else {
                    echo "<br /><center>Potvrzovací heslo se neshoduje s novým.</center><br />";
                } 
            } else {
                echo "<br /><center>Staré heslo se neshoduje.</center><br />";
            }
        }
?>

<?php if(isset($_SESSION['username'])) { ?>
<form name="changepassword" method="post" action="">  
    <input type="password" name="oldpassword" class="input-original" placeholder="Staré heslo" />
    <input type="password" name="newpassword" class="input-original" placeholder="Nové heslo" />
    <input type="password" name="confirmnewpassword" class="input-original" placeholder="Potvrdit nové heslo"/>
    <button class="btn" type="submit" name="changepass">Změnit heslo</button>
</form>
<?php } else { 
        echo "Uživatel není přihlášen";
      }
?>

User.php

    public static function passwordVerify($username,$password){
        $query = Database::run("SELECT * FROM users WHERE username = '".$username."'");
        $result = mysqli_fetch_array($query);
        if(password_verify($password, $result['password'])) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public static function changePassword($username,$newPassword) {
        $hashed_password = self::hash($newPassword, ['cost' => 12]);
        $hash = Database::run("UPDATE users SET password = '".$hashed_password."' WHERE username = '".$username."'");   
        return $hash;
    }

Díky moc za rady.

Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:a5ea:8...–
David
~ Anonymní uživatel
177 příspěvků
30. 6. 2017   #2
-
0
-

#1 David
Omlouvám se byla to jen moje nepozornost :) 

Pro info: Chyba byla v argumentu u funkce: 

$changePassword = User::changePassword($username,$oldPassword,$newPassword);

Změněno na

$changePassword = User::changePassword($username,$newPassword);
Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:a5ea:8...–
Kit+15
Guru
30. 6. 2017   #3
-
0
-

#2 David
Do stejného místa jsem došel také. Mezitím jsem zjistil, že tam máš SQL injection, které by sis asi měl opravit.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
David
~ Anonymní uživatel
177 příspěvků
8. 7. 2017   #4
-
0
-

#3 Kit
Kde konkrétně myslíš teď ? 

Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:7c4b:d...–
Kit+15
Guru
8. 7. 2017   #5
-
0
-

#4 David
Nemáš patřičně ošetřené $username v SQL dotazu.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
David
~ Anonymní uživatel
177 příspěvků
9. 7. 2017   #6
-
0
-

To nestačí ošetřit jen vstup z webu ? Jak by si ošetřil SQL ? Předpokládám, že je lepší nevkládat přímo proměnnou.

Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:7ca2:f...–
Kit+15
Guru
9. 7. 2017   #7
-
0
-

#6 David
Vstup z webu určitě ošetřený nemáš, takže nestačí. Záleží na použité databázi a ovladači. SQL ošetřuji pomocí prepared statements v PDO.

Dá se použít i metoda quote() v PDO nebo funkce mysqli_real_escape_string() v MySQLi.

BTW: Koukám, že použitá třída "Database" je docela k ničemu, když ji voláš staticky a neposkytuje objekt na výstupu.
 

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:bdd9:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
David
~ Anonymní uživatel
177 příspěvků
9. 7. 2017   #8
-
0
-

#7 Kit
Vždyť mam u každého $_POST - funkci - validForm, která ošetřuje vstup.

    public function validForm($data) {
        $data = trim($data);
        $data = stripcslashes($data);
        $data = htmlspecialchars($data);
        $data = mysqli_real_escape_string(Database::connect(),$data);
        return $data;
    }
Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:7ca2:f...–
Kit+15
Guru
9. 7. 2017   #9
-
0
-

#8 David
Funkce htmlspecialchars() tam nepatří, o užitečnosti stripcslashes() silně pochybuji - nikdy jsem ji nepotřeboval. Data se mají ošetřovat až při ukládání do databáze, aby nebylo pochyb o tom, co ošetřené je a co není. Stačí na to jedna standardní metoda.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
10. 7. 2017   #10
-
0
-

#9 Kit

Tak jsem si udělal ošetření, stačí to takto ?

Ber to jako příklad u jedné funkce na vložení, zbytek pak dodělám.

Jinak díky i za připomínku k třídě Database, už jsem to předělal na "nestatickou" třídu.

Database.php

    protected function prepareSQL($query) {
        $stmt = $this->con->prepare($query);
        return $stmt;
    }

Article.php

    public function addArticle($news_title,$news_url,$news_full_content) {
        $date = date("Y-m-d H:i:s");
        $news_author = $_SESSION['username'];
        $query = "INSERT INTO articles (news_title,news_url,news_full_content,news_author,news_published_on) VALUES('$news_title','$news_url','$news_full_content','$news_author','$date')";
        if($stmt = $this->prepareSQL($query)) {
            $result = $this->run($query);
            return $result;
        } else {
            echo "Nepodařilo se vložit tento kód";
        }
    }
Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
10. 7. 2017   #11
-
0
-

#10 kiCkZ
Ne, tohle je zcela mimo. Koukám, že jsem včera neodeslal skript s příkladem řešení. 

$query = "INSERT INTO articles (news_title, news_url, news_full_content, news_author, news_published_on) VALUES(?, ?, ?, ?)";
$insert = $pdo->prepare($query);
$insert->execute(array($news_title, $news_url, $news_full_content, $news_author, $date));

Všimni si, že zcela zmizely apostrofy.

Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
10. 7. 2017   #12
-
0
-

#11 Kit

Problém je, že proměnnou $pdo nemam, ve třídě Database mam pouze v konstruktoru přiřazenou funkci connect do:  private $con.

Tím pádem v Article třídě nemam možnost dostat se do execute funkce, jelikož toto je ve třídě Article, která dědí z Database.

I když nastavim $con na protected, tak to ve třídě Article nejde odkazovat na execute a prepare().

Database.php

class Database { 
    
    private $con;
            
    function __construct() {
        $this->con = $this->connect();
    }
    
    protected function connect(){
        $this->con = new mysqli(DB_HOST,DB_USERNAME,DB_PASSWORD,DB_NAME); 
        $this->con->set_charset("utf8");
        if(mysqli_connect_errno()) {
            echo 'Připojení k databázi se nezdařilo: ' . mysqli_connect_error();
        } 
        return $this->con;
    }
    
    // close connection
    protected function close() {
        mysqli_close($this->connect());
    }
    
    protected function run($query) {
        $result = mysqli_query($this->connect(),$query);
        return $result;        
    }
}

Article.php

class Article extends Database {   
    
    public function addArticle($news_title,$news_url,$news_full_content) {
        $date = date("Y-m-d H:i:s");
        $news_author = $_SESSION['username'];
        $query = "INSERT INTO articles (news_title,news_url,news_full_content,news_author,news_published_on) VALUES(?,?,?,?,?)";
        $insert = $pdo->prepare($query);
        $insert->execute(array($news_title, $news_url, $news_full_content, $news_author, $date));
    }
}
Nahlásit jako SPAM
IP: 94.113.255.–
kiCkZ0
Newbie
10. 7. 2017   #13
-
0
-

#11 Kit
Píše mi to stále hlášku:

Warning: mysqli_stmt::execute() expects exactly 0 parameters, 1 given in C:\xampp\htdocs\CMS\admin\libraries\article.php on line 11

Article.php

    public function addArticle($news_title,$news_url,$news_full_content) {
        $date = date("Y-m-d H:i:s");
        $news_author = $_SESSION['username'];
        $query = "INSERT INTO articles (news_title,news_url,news_full_content,news_author,news_published_on) VALUES(?,?,?,?,?)";
        $stmt = $this->con->prepare($query);
        $stmt->execute(array($news_title,$news_url,$news_full_content,$news_author,$date));        
    }
Nahlásit jako SPAM
IP: 94.113.255.–
weroro0
Návštěvník
10. 7. 2017   #14
-
0
-

#13 kiCkZ
Do $stmt->execute() nepatrí žiadny argument a ty mu tam strkáš pole.

Dáta sa posielajú pomocou  

$stmt->bind_param('ssss', $news_title, $news_url, $news_full_content, $news_author,$date);

A až potom zavoláš $stmt->execute();

Nahlásit jako SPAM
IP: 91.235.54.–
Javascript (ES5, ES6+) / Typescript Developer, Vanilla Front-end ninja, HTML, CSS specialist

Hlúpa otázka vzniká ako reakcia na nedostatok relevantných informácií.
kiCkZ0
Newbie
10. 7. 2017   #15
-
0
-

#14 weroro
Protože jsem to bral podle kódu víše.

Už jsem zjistil kde je přímo problém a mam to funkční.

Díky za info

Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
10. 7. 2017   #16
-
0
-
Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
weroro0
Návštěvník
10. 7. 2017   #17
-
0
-
Nahlásit jako SPAM
IP: 91.235.54.–
Javascript (ES5, ES6+) / Typescript Developer, Vanilla Front-end ninja, HTML, CSS specialist

Hlúpa otázka vzniká ako reakcia na nedostatok relevantných informácií.
kiCkZ0
Newbie
10. 7. 2017   #18
-
+1
-
Zajímavé
Kit +

Nakonec jsem to vyřešil takto:

    public function addArticle($news_title,$news_url,$news_full_content) {
        $date = date("Y-m-d H:i:s");
        $news_author = $_SESSION['username'];
        $query = "INSERT INTO articles (news_title,news_url,news_full_content,news_author,news_published_on) VALUES(?,?,?,?,?)";
        $stmt = $this->con->prepare($query);
        $stmt->bind_param("sssss",$news_title,$news_url,$news_full_content,$news_author,$date);
        if($stmt->execute()) {
            return TRUE;
        } else {
            return false;
        }        
    }
Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
10. 7. 2017   #19
-
0
-

#17 weroro
Myslíš si, že dnes ještě má smysl používat MySQLi, když se ho PHP chce v budoucnu zbavit? PDO toho umí víc.

Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
weroro0
Návštěvník
10. 7. 2017   #20
-
0
-

#19 Kit
Je ešte pomerne hudbou budúcnosti, úplnej nepodpory mysqli. Netvrdím, že PDO nie je lepšie, iba som mu chcel poradiť a nie ho nútiť použiť niečo iné. On to mal pomocou mysqli::, čo nie je chyba ako keby používal dnes už nepodporované mysql.
Ja osobne napr. nevidím v dnešnej dobe význam v relačných databázach, pokiaľ sa jedná iba o content webu (články a pod.), žijeme v dobe noSQL ako je napr. veľmi výkonný Elastic.

#18 kiCkZ
Môže byť. Tú podmienku môžeš ale zrušiť ak ti stačí true/false a skráť to iba na
 

return $stmt->execute();

To ti tiež vráti true alebo false.
Ešte byť tebou pre istotu testujem, či existuje tá SESSION.

$news_author = !empty($_SESSION['username']) ? $_SESSION['username'] : false;

a ak je false, tak nevykonáš insert alebo niečo iné.

Nahlásit jako SPAM
IP: 91.235.54.–
Javascript (ES5, ES6+) / Typescript Developer, Vanilla Front-end ninja, HTML, CSS specialist

Hlúpa otázka vzniká ako reakcia na nedostatok relevantných informácií.
kiCkZ0
Newbie
10. 7. 2017   #21
-
0
-

#20 weroro
Ok, jen se chci zeptat je tedy lepší do budoucna PDO ? Než MySQLI ? Nebo je ještě nějaká možnost ?

Píšu samozřejmě OOP. Popřípadě další rady.

Nahlásit jako SPAM
IP: 94.113.255.–
weroro0
Návštěvník
10. 7. 2017   #22
-
0
-

#21 kiCkZ
Nepodpora mysqli je ešte hudbou niekoľkých rokov. Do vtedy to ešte 5x celé prepíšeš. :-) Nemusíš sa báť.

PDO je dobrá voľba ale je to až priveľmi robusné na malé veci. Byť tebou skúsim napr. DiBi (https://dibiphp.com/cs/). Spomínaný Elastic (https://www.elastic.co/products/elasticsearch) je pre hardcore užívateľov, lebo ho na bežnom hostingu nerozbeháš.

Nahlásit jako SPAM
IP: 91.235.54.–
Javascript (ES5, ES6+) / Typescript Developer, Vanilla Front-end ninja, HTML, CSS specialist

Hlúpa otázka vzniká ako reakcia na nedostatok relevantných informácií.
kiCkZ0
Newbie
10. 7. 2017   #23
-
0
-

#22 weroro
Děkuju a máš pravdu PDO co jsem si teď projel je mnohem lepší.

Začnu to co mam přepisovat, protože nerad bych dělal něco co nemá výsledek do budoucna.

Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
10. 7. 2017   #24
-
0
-

#21 kiCkZ
Pokud píšeš objektově (z uvedených příkladů to moc patrné není), je lepší volbou PDO právě kvůli objektovosti. Jako výsledek SQL dotazu ti může dodat objekt nebo kolekci objektů, což se docela hodí například do výstupních šablon.

Přes PDO bez problémů pracuji i s databázemi PostgreSQL a SQLite. Jednoduché dotazy bývají stejné a metoda quote() dělá escapování podle druhu databáze. Na složitější věci se vždy můžeš zeptat na typ databáze reflexí, ale takové záležitosti raději řeším dotazem CALL, který tě od konkrétní databáze také dobře odstíní.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:ec3e:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
10. 7. 2017   #25
-
0
-

#24 Kit
Děkuji ti mockrát za rady.

Jen se tě ještě zeptám ma jednu věc.

Momentálně mam systém napsaný tak, že mam složku, kde jsou třídy a dělají vkládání do DB a připojují se k db, vypisují hodnoty apod. a pak mam klasické soubory u indexu, kde mam třeba funkce jako isset po kliknutí. Dám sem zase příklad.

User.php

class User extends Database {
    
    public function createNewUser($username, $password, $email) {
        $hashed_password = $this->hash($password, ['cost' => 12]);
        $query = "INSERT INTO users (username,password,email,role) VALUES('$username','$hashed_password','$email','guest')";
        $result = $this->run($query);
        return $result;
    }

    public function hash($password, array $options = []) {
        
        if (isset($options['cost']) && ($options['cost'] < 4 || $options['cost'] > 31)) {
            throw "Cost must be in range 4-31, $options[cost] given.";
        }

        $hash = password_hash($password, PASSWORD_BCRYPT, $options);
        if ($hash === FALSE || strlen($hash) < 60) {
            throw 'Hash computed by password_hash is invalid.';
        }
        return $hash;
    }
    
    public function checkUsernameExist($username) {
        $query = $this->run("SELECT username FROM users WHERE username = '$username'");
        $result = mysqli_num_rows($query);
        if($result > 0) {
            return FALSE;
        } 
            return TRUE;
    }   

    public function checkEmailExist($email) {
        $query = $this->run("SELECT email FROM users WHERE email = '$email'");
        $result = mysqli_num_rows($query);
        if ($result > 0) {
            return FALSE;
        }
            return TRUE;
    }

    public function login($username, $password) {
            $query = $this->run("SELECT * FROM users WHERE username = '$username'");
            $result = mysqli_fetch_array($query);
            $count = mysqli_num_rows($query);
            if ($count == 1) {
                if(password_verify($password, $result['password'])) {
                    $_SESSION['id'] = $result['id'];
                    $_SESSION['username'] = $result['username'];
                    $_SESSION['email'] = $result['email'];
                    $_SESSION['role'] = $result['role'];
                    return TRUE;
                } else {
                    echo "<center><p>Nesprávné heslo.</p></center>";
                }
            } else {
                echo "<center><p>Nesprávné uživatelské jméno.</p></center>";
            }
    }

    public function is_loggin() {
        if(isset($_SESSION['username'])) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public function redirect($url) {
        header("location: index.php");
    }

    public function logout() {
        session_unset();
        session_destroy();
        header('Location:'.$url->diradmin.'login.php');
        return true;
    }    
    
    public function passwordVerify($id,$password){
        $query = $this->run("SELECT * FROM users WHERE id = '$id'");
        $result = mysqli_fetch_array($query);
        if(password_verify($password, $result['password'])) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public function changePassword($id,$newPassword) {
        $hashed_password = $this->hash($newPassword, ['cost' => 12]);
        $hash = $this->run("UPDATE users SET password = '$hashed_password' WHERE id = '$id'");   
        return $hash;
    }

}

A pak mam soubory, kde to vkládám jako funkce přes objekty.

<?php 
    require_once $_SERVER['DOCUMENT_ROOT'].'/CMS/vendor/autoload.php'; 
    session_start();
    
    $url = new url;
    $formValid = new Security;
    $user= new User;
?>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scal=1">
        <meta name="description" content="">
        <meta name="author" content="">
        <title>| Anywhere.cz</title>
        <link rel="stylesheet" href="../admin/css/admin.css">
        <script src="../admin/js/tinymce/tinymce.js"></script>
        <script src="../admin/js/tinymce/init-tinymce.js"></script>
    </head>
    <body>
    <div id="main" class="layout-column-main">
        <div class="admin-bar clearfix">
            <a class="logo-wrapper" href="<?php echo $url->diradmin; ?>admin.php" title="Anywhere System"><span class="logo-system"></span></a>
                <ul class="admin-bar-ul">
                    <li class="admin-bar-list-li">
                        <a href="login.php" class="admin-bar-list-inside">Přihlášení</a>
                    </li>
                    <li class="admin-bar-list-li">
                        <a href="register.php" class="admin-bar-list-inside">Registrace</a>
                    </li>
                    <li class="admin-bar-list-li">
                        <a class="admin-bar-list-inside" href="<?php echo $url->dir; ?>index.php">Hlávní stránka</a>
                    </li>
                </ul>
        </div>
        <div class="flex-column">
<?php include_once 'templates/content.php'; ?>
<?php 
    
    if(isset($_POST['login'])) {
        $username = $formValid->validForm($_POST['username']);
        $password = $formValid->validForm($_POST['password']);
        $user = $user->login($username, $password);
            if($user) {
                header('location:'.$url->diradmin.'admin.php');
            } 
    }
?>
<form class="form_align" method="post" action="">
    <input class="input-login-reg" type="text" name="username" placeholder="&nbsp;&nbsp;Uživatelské jméno" required />
    <input class="input-login-reg" type="password" name="password" placeholder="&nbsp;&nbsp;Zadejte vaše heslo" required />
    <button class="btn-login-reg" type="submit" name="login">Přihlásit se</button>
</form>
<?php include_once 'templates/footer.php'; ?>

Je tento postup správný ? Nebo to jde nějak ještě lépe, aby i v budoucnu jsem měl kód přehlednější a upravenější. Jinak toho MySQLi si nevšímej, ještě to musim předělat :D

Díky moc

Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:8dd1:a...–
Kit+15
Guru
10. 7. 2017   #26
-
0
-

#25 kiCkZ
Celé se mi to číst moc nechce, ale pár věcí ti vytknu: 

class User extends Database

Tohle je zcela špatně, protože User není Database. Slovo "extends" používej jen tam, kde místo něj můžeš s klidem použít české slovo je. Správně je tedy použití kompozice, kdy databázi vložíš přes parametr do třídy User. Tím se ty třídy stanou nezávislé a budeš je libovolně zaměnit za jiné třídy se stejným rozhraním.

Můžeš klidně napsat 

return $result > 0;

a bude to fungovat úplně stejně jako ta konstrukce z ifů. Ovšem jako nejlepší se mi jeví prostý 

return $result;

který je mnohem použitelnější a srozumitelnější. Lepší je už jen throw Exception, který tě v případě chyby odstíní od různých stavových kódů a nahradí je srozumitelnou hláškou.

Časem možná přijdeš na to, že místo volání metody $user->createNewUser() bude přehlednější a jednodušší volání $user->create(). Jednotné pojmenování metod ve třídách má mnoho výhod a zbaví tě nutnosti přejmenovávání v budoucnu (někteří tomu říkají refaktorování, ale to je něco jiného).

Místo funkce hash() se nauč používat funkci crypt(), která to umí lépe a hlavně stejné heslo zašifruje pokaždé jinak, takže je odolnější proti útokům.
 

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
11. 7. 2017   #27
-
0
-

#26 Kit
Mohl by si mi dát jen nějaký praktický příklad té kompozice ? 

Myslíš to takto:

class Articles {    

	private $pdo;
    
    	function __construct() {
       		$this->pdo = new Database;
    	}
}

Díky

Nahlásit jako SPAM
IP: 94.113.255.–
kiCkZ0
Newbie
11. 7. 2017   #28
-
0
-

Nedaří se mi nyní vůbec v Article tříde volat funkce databáze a stejně tak ani přímo ve "view" stránkách.

Bez slovíčka extends mi vůbec nefunguje ta proměnná, jak si tedy myslel tu svou verzi ? 

A jak to popřípadě implementovat do již zmiňované "view" stránky.

class Article extends Database{ 
    
    private $pdo;
            
    function __construct() {
        $this->pdo = new Database;
    }
}
Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
11. 7. 2017   #29
-
0
-

#28 kiCkZ
 

$db = new Database($config);
$user = new User($id, $username, $email, $role);
$db->add($user);
$db->login($user);
$db->delete($user);

atd. Implementaci snad zvládneš. Ve třídě Database to pak vypadá asi takto:

class Database { 
    
    private $con;
            
    function __construct($config) {
        $this->con = new mysqli($config->host, $config->username, $config->password, $config->dbname);
        if ($this->con->connect_error) {
            throw new Exception(
                'Připojení k databázi se nezdařilo: ' .
 $this->con->connect_error,                $this->con->connect_errno
            );
        }
        $this->con->set_charset("utf8");    }

    function add($data) {
        $data->add($this->con);
    }
}

Zbytek snad zvládneš implementovat ve třídě User.

Třídu Database mám rozdělenu na dvě, abych mohl mít různé databáze a používat je dle potřeby. Nechtěl jsem to však komplikovat.

BTW: Ten zdejší editor je příšerný.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:ec3e:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
11. 7. 2017   #30
-
0
-

#29 Kit

Prosimtě a ten horní kód dáváš kam ? Jako nejdříve jsem slyšel jak je PDO super, tak jsem udělal celé PDO Database.php a teď to máš v mysqli, tak já už fakt nechápu jak to mam dělat.

V druhém případě vůbec nechápu, proč máš add funkci ve vlastní funkci ? Co to má za význam ?

$config je definován kde ? Potřebuji to když už nějak kompletně, nejsem letitý profesionál věnuji se tomu asi 3 týdny.

Další věc, s tímto kódem my nefungují funkce execute ani prepare ? Jak mam pak implementovat PDO ? 

Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:4c3a:1...–
Kit+15
Guru
11. 7. 2017   #31
-
0
-

Ten horní kód dávám do controlleru. Je to vlastně sestavení tří různých pořadavků na databázi - použiješ samozřejmě vždy jen jeden.

Ve druhém případě to tak mám proto, aby se mi třída Database nenafoukla. Databázové dotazy jsou pak umístěny ve třídě User. Přidání dalších tříd (např. Article, Author, Car,...) je pak jednoduché podle jednotného vzoru. Říká se tomu dvojitá inverze závislostí.

Pokud bys to chtěl prostou injekcí závislosti, volání by vypadalo asi takhle: 

$db = new Database($config);
$user = new User($id, $username, $email, $role);
$user->add($db);
$user->login($db);
$user->delete($db);

Na můj vkus to vypadá divně, proto to mám přehozené.

Poslal jsi mi zdroják v MySQLi, tak jsem ti ho opravil v MySQLi. Jen jsem ho nepřepsal do PDO.

V $config mám přece ty přihlašovací údaje do databáze. Proč bych to měl mít ve čtyřech globálních konstantách DB_HOST, DB_USERNAME, DB_PASSWORD a DB_NAME, když to můžu mít v jednom objektu $config? Ušetřím 3 parametry konstruktoru a je to přehlednější.

Tak si to přepiš do PDO. Není to tak těžké.
 

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:ec3e:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ
~ Anonymní uživatel
28 příspěvků
11. 7. 2017   #32
-
0
-

A jak to mas volané ten config ?
Nevidím nikde nic jen najednou parametr ve funkci s odkazovanim.

Zasláno z mobilního telefonu.

Nahlásit jako SPAM
IP: 2001:1ae9:19e:c200:88e9:4...–
Kit+15
Guru
12. 7. 2017   #33
-
0
-

#32 kiCkZ
To si beru funkcí parse_ini_file() z konfigurace, abych neměl hesla v aplikaci. Je to kvůli verzování a provozu stejné aplikace na různých serverech s odlišnými přihlašovacími údaji k databázi.

Pokud více hodnot patří k sobě, je vhodné je zapouzdřit do jednoho objektu a manipulovat s nimi jako s celkem. Kandidáty na zapouzdření poznáš typicky podle stejné předpony, ve tvém případě předpony "DB_".

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ
~ Anonymní uživatel
28 příspěvků
12. 7. 2017   #34
-
0
-

Takže config mas jako samostatnou třídu a v ni mas login údaje do DB ? A jak to pak nasdilis třídě class ? Přes Require_once nebo extended ?

Zasláno z mobilního telefonu.

Nahlásit jako SPAM
IP: 217.77.165.–
kiCkZ0
Newbie
12. 7. 2017   #35
-
0
-

Ještě dotaz pokud mam takto udělaný Database class s PDO, jak mam "sdílet" funkci prepare do třídy třeba USER apod. ? Chci ty SQL dotazy mít konkrétně ve třídě které se to týká.

Už jsem na tom strávil 2 dny a pořád mi to nejde.

class Database { 
    
    private $db_dsn = 'mysql:host=localhost;dbname=cms';
    private $db_username = "root";
    private $db_password = "";
    private $pdo;
    
    public function __construct() {
        try {
            $this->pdo = new PDO($this->db_dsn, $this->db_username, $this->db_password);
            $this->pdo->exec('SET NAMES utf8');
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            throw new Exception ("Problém s přihlášením do databáze: ").$e->getMessage();
        }
        return $this->pdo;  
    }

        protected function disconnect() {
        $this->pdo = NULL;
    } 
}   
Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
12. 7. 2017   #36
-
0
-

#34 kiCkZ
Je to jen jeden řádek. Přece kvůli němu nebudu dělat třídu.

$config = (object) parse_ini_file('.htconfig.ini', true);

V souboru .htconfig.ini je pak konfigurace: 

host = localhost
username = user
password = p123456
dbname = test

Je to klasický databázový typ INIFILE z Windows, umí to i sekce.

Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Kit+15
Guru
12. 7. 2017   #37
-
0
-

#35 kiCkZ
Však jsem ti to už psal, databázi si dáš jako parametr metody nebo naopak. Důležitá je ta volná vazba, takže stejný objekt můžeš poslat místo do databáze třeba jako XML nebo JSON.

Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
12. 7. 2017   #38
-
0
-

#37 Kit
Psal si mi to, ale nefunguje to.

Potřebuji toto:

Database.php

class Database { 
    
    private $db_dsn = 'mysql:host=localhost;dbname=cms';
    private $db_username = "root";
    private $db_password = "";
    private $pdo;
    
    public function __construct() {
        try {
            $this->pdo = new PDO($this->db_dsn, $this->db_username, $this->db_password);
            $this->pdo->exec('SET NAMES utf8');
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            throw new Exception ("Problém s přihlášením do databáze: ").$e->getMessage();
        }
        return $this->pdo;  
    }

        protected function disconnect() {
        $this->pdo = NULL;
    } 
}   

User.php

 Nefungují mi vůbec funkce jako execute, prepare apod. vůbec to na ně neodkazuje.

Parametr v konstruktoru mam a do každé funkce to snad psát nemusim ne ?

class User {

	private $pdo;

    	public function __construct(Database $db) {
        	$db = new Database;
		$this->pdo = $db;
    	}
    
  	public function vypisNeco() {
		$query = $this->pdo->query();
	} 


}
Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
12. 7. 2017   #39
-
0
-

#38 kiCkZ

class User {
        private $name;
        private $email;

    	public function __construct($name, $email) {
		$this->name = $name;
		$this->email = $email;
    	}
    
  	public function vypisNeco($pdo) {
		return $pdo->query("SELECT * FROM User");
	} 
}
Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
12. 7. 2017   #40
-
0
-

#39 Kit
Nefunkční:

Uncaught Error: Call to undefined method Database::query() in

Budu se opakovat, ale ve třídě User se ta funkce "query" vůbec nevypíše.

Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
12. 7. 2017   #41
-
0
-

#40 kiCkZ
Proč ve třídě Database nemáš metodu query(), když ji voláš?

Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
12. 7. 2017   #42
-
0
-

#41 Kit
Aha, takže všechny funkce jako execute apod. musim zavolat nejdříve v Database třídě a pak je jen jako objekt zavolat na stránce, kde je chci vypsat ? 

Ale v každé funkci musim volat parametr $pdo neni možné to nějak automatizovat ?

Nahlásit jako SPAM
IP: 94.113.255.–
Kit+15
Guru
12. 7. 2017   #43
-
0
-

#42 kiCkZ
Všechny metody nemusíš ve třídě Database implementovat, ale jen ty, které potřebuješ. Zrovna metodu execute() nepotřebuješ, protože ta ve třídě PDO není. Také si můžeš některá sekvenční volání sdružit.

Třída Database je ve tvém případě podle vzoru Adaptér. Co ji naučíš, to bude umět. Můžeš ji naučit i tu metodu execute() nebo třeba insert($tabulka, $data). Vymysli si nějaké vhodné rozhraní, implementuj a používej.

Nahlásit jako SPAM
IP: 85.93.112.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
kiCkZ0
Newbie
12. 7. 2017   #44
-
0
-

#43 Kit
Takže pokud budu chtít ošetřit před SQL injection, tak mi stačí udělat metodu prepare, např:

$pdo->prepare("SELECT * FROM users WHERE username = ?");

$pdo->query(array($username));

Můj předchozí dotaz ještě zněl, zda musim v každé funkci volat $pdo ? 

Nebo je jiný způsob (lepší) ?

Můj původní plán byl takový, že jsem chtěl, aby to fungovalo tak, že databáze sice bude mít svoje funkce, nicméně poté budu moct například ve třídě User volat tímto způsobem nicméně přes PDO.

    public function checkUsernameExist($username) {
        $query = $this->run("SELECT username FROM users WHERE username = '$username'");
        $result = mysqli_num_rows($query);
        return $result;
    }   

Ale nyní bych musel dát další parametr do funkce a ten pal při objektu volat a vůbec nwm, jak bych měl nahradit tu funkci num_rows, zřejmě bych musel znovu vytvořit nějakou funkci v Database třídě, kterou pak napáruju a tím se mi vytváří další otázka, jak to potom zavolat, když do teď to bylo takto. 

<?php 
    
    if(isset($_POST['register'])){  
        $username = $formValid->validForm($_POST['username']);  
        $password = $formValid->validForm($_POST['password']);
        $confirm_password = $formValid->validForm($_POST['confirm_password']);
        $email = $formValid->validForm($_POST['email']);
        if ($password == $confirm_password){
            $check_username = $user->checkUsernameExist($username);
            $check_email = $user->checkEmailExist($email);
            if($check_username == true){
                if($check_email  == true) {
                    $register = $user->create($username, $password, $email);
                    if($register){
                        header("Location: login.php?registered=true");   
                    } else {
                        echo '<div class="error-message">Registrace neproběhla úspěšně</div>';
                    }
                } else {
                    echo '<div class="error-message">Tento email již existuje</div>';
                }
            } else {
                echo '<div class="error-message">Uživatelské jméno už existuje.</div>';
            }
        } else {
            echo '<div class="error-message">Hesla nesouhlasí, zadejte heslo znovu.</div>';
        }
    } 
?>

Přijde mi lepší u ověření funkce mít parametr jen $username než pak zase dávat při volání parametr jako

proměnnou objektu databáze. 

Nahlásit jako SPAM
IP: 94.113.255.–
Melamber7770
Newbie
12. 7. 2017   #45
-
0
-

#44 kiCkZ
pokud tam máš tolik if řeš to pomocí switche.jinak zajímavé příklady kluci.

Nahlásit jako SPAM
IP: 37.48.39.–
Kit+15
Guru
13. 7. 2017   #46
-
0
-

#45 Melamber777
Switch není třeba. Stačí vyházet všechny "else" a rázem se to zjednoduší. I to šílené odsazení zmizí.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:5c43:...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 14 hostů

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý