PHP-Einfach.de
  • PHP Tutorial
  • MySQL Tutorial
  • Für Fortgeschrittene
  • Webhosting
  • Forum

Codeschnipsel

PHP Login ab PHP 5.3.7 mit MySQLi

Zurück zur Übersicht
Um die Grundlagen in PHP und MySQL zu vertiefen, eignen sich eigene kleine Skripte, die sich nicht auf WordPress, Typo3 etc. beziehen. In diesem Tutorial möchte ich die alte Methode des Loginsystem auf PHP-Einfach ablösen und euch auf den neusten Standard bringen.

Um diese Methode benutzen zu können ist die PHP Version 5.3.7 vorausgesetzt, denn es werden Funktionen benutzt die erst ab der PHP Version 5.5 verfügbar sind. Dank der password_compat von ircmaxell aus GitHub ist es uns aber schon möglich die benötigten Funktionen schon ab der PHP Version 5.3.7 zu verwenden.

Schritt 1: Installation und erstes Testen
Um die neue Password_* Funktionen ab der PHP Version 5.3.7 benutzen zu können, benötigen wir die Datei von ircmaxell, welche man hier downloaden kann. Nach dem Download legt ihr euch so wie ich, einen Unterordner mit dem Namen inc an und legt dort die heruntergeladene password_compat.php ab.
Nun erstellen wir uns im Hauptverzeichnis eine index.html und eine check.php an. In der check.php schreiben wir folgenden Code, direkt zu Anfang der Datei hinein:

<?php
session_start
();

if ((
version_compare(PHP_VERSION, '5.3.7') >= 0)
     && (
version_compare(PHP_VERSION, '5.5.0') < 0)) {
    require_once(
dirname( __FILE__ ) . '/inc/password_compat.php');
}

Um zu testen, ob die benötigten Funktionen nun auch enthalten sind, schreiben wir nach der If-Anweisung folgenden Code hinein:
echo password_hash('test', PASSWORD_BCRYPT);

Unser Code sieht nun folgender maßen aus:

<?php
session_start
();

if ((
version_compare(PHP_VERSION, '5.3.7') >= 0)
     && (
version_compare(PHP_VERSION, '5.5.0') < 0)) {
    require_once(
dirname( __FILE__ ) . '/inc/password_compat.php');
}

echo 
password_hash('test', PASSWORD_BCRYPT);


Das oben gezeigte Beispiel erzeugt eine ähnliche Ausgabe: $2y$10$ndh.9cKGK4XSU4syTyU.vemimYKxnax8VKLWD6Ucyt4q6fKP3JeqW

Wenn alles funktioniert hat, dann sind die Funktionen erfolgreich installiert. Im nächsten Schritt widmen wir uns der optimalen Konfiguration der Passwort Verschlüsselung.

Schritt 2: Optimale Konfiguration
Nach der Installation der Funktionen widmen wir uns der Konfiguration des SALT und des COST. Der SALT ist eine zufällig gewählte Zeichenfolge die im Klartext an das verschlüsselte Passwort angehängt wird, welche die Entropie der Eingabe erhöht. Der COST hingegen definiert wie oft das Passwort verschlüsselt werden soll. Um einen guten COST zu finden, empfiehlt es sich eine weitere Datei im Hauptverzeichnis zu erstellen, welche danach wieder gelöscht werden kann.

<?php
/**
 * This code will benchmark your server to determine how high of a cost you can
 * afford. You want to set the highest cost that you can without slowing down
 * you server too much. 8-10 is a good baseline, and more is good if your servers
 * are fast enough. The code below aims for > 500 milliseconds stretching time,
 * which is a good baseline for systems handling interactive logins.
 */
$timeTarget = 0.5; // 500 milliseconds 

$cost = 4;
do {
    
$cost++;
    
$start = microtime(true);
    
password_hash('test', PASSWORD_BCRYPT, ['cost' => $cost]);
    
$end = microtime(true);
} while ((
$end - $start) < $timeTarget);

echo 
'Appropriate Cost Found: ' . $cost;
Das Ergebnis verwenden wir als COST. Als SALT empfehle ich die Verwendung von mcrypt. In meinem Beispiel haben sich folgende Einstellungen ergeben:

<?php
session_start
();

if ((
version_compare(PHP_VERSION, '5.3.7') >= 0)
     && (
version_compare(PHP_VERSION, '5.5.0') < 0)) {
    require_once(
dirname( __FILE__ ) . '/inc/password_compat.php');
}

$options = array(
    
'cost' => 13,
    
'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)
);

echo 
password_hash('test', PASSWORD_BCRYPT, $options);
Das oben gezeigte Beispiel erzeugt eine ähnliche Ausgabe: $2y$09$vRtUHQJ2dldbCN0Y5iC1jOabVJcvMV243rwNagOPFT14LVxqAOtDa

Schritt 3: Das HTML Formular
Nachdem wir die benötigten Funktionen installiert und konfiguriert haben, widmen wir uns dem HTML Formular, welches später unseren Login abfragen soll. Ich verwende in diesem Beispiel ein ganz einfaches Formular, welches den Benutzernamen und das Passwort erfordert.

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8"> 
<title>Mein Loginsystem</title> 
</head> 
<body style="font-family:Arial, Helvetica, sans-serif;"> 
<div style="border-radius:40px;padding:40px;background:#CCC;width:366px;box-shadow:rgba(0,0,0,.1) 5px 5px 5px;height:120px;position:absolute;top:50%;left:50%;margin-top:-150px;margin-left:-173px;"> 
<form action="check.php" method="post"> 
<div style="height:30px;"> 
<label for="benutzer" style="display:inline-block;width:48%;font-size:18px;">Benutzername:</label> 
<input type="text" name="username" id="benutzer" style="height:10px;padding:5px;"> 
</div> 
<div style="height:45px;"> 
<label for="verifikation" style="display:inline-block;width:48%;font-size:18px;">Passwort:</label> 
<input type="password" name="password" id="verifikation" style="height:10px;padding:5px;"> 
</div>
<div style="height:30px;"> 
<input type="submit" value="Einloggen!" style="height:30px;width:100%;">
</div>
</form> 
</div> 
</body> 
</html>

Schritt 4: Verifizieren mit password_verify()
In diesem Schritt schreiben wir das PHP Script um uns später authentifizieren zu können. Ich beziehe mich hierbei auf das aus Schritt 3 geschriebene HTML Formular. Als erstes stellen wir eine Abfrage, welche überprüft ob unser Formular abgesendet worden ist. Dazu gehen wir in unsere check.php und schreiben an den Anfang der Datei, noch vor dem einbinden der password_compat.php

<?php

if((empty(trim($_POST['username'])))
    || (empty(
$_POST['password']))) {
    exit();
}

// … Der vorher geschriebene Code

Mit dieser Abfrage überprüfen wir ob das Formular abgesendet worden ist. Für den Produktiveinsatz wird diese Methode zur Überprüfung ob das Formular abgesendet worden ist, nicht EMPFOHLEN!!! , da wir uns mit den neuen password_* Funktionen beschäftigen. Um das Passwort nun dem Usernamen zu verifizieren benutzen wir die password_verify() Funktion und fragen im nächsten Schritt ob auch das Passwort aktualisiert werden muss, weil wir zum Beispiel vor geraumer Zeit den SALT oder den COST aktualisiert haben.

<?php

if(password_verify($_POST['password'], password_hash($_POST['password'], PASSWORD_BCRYPT, $options))) {
    if(
password_needs_rehash(password_hash($_POST['password'], PASSWORD_BCRYPT, $options), PASSWORD_BCRYPT, $options)) {
        .. 
// Neues Passwort speichern
    
}
    echo 
'Das Passwort war korrekt. Hier geht es weiter!';
} else {
    echo 
'Das Passwort war nicht korrekt. Versuche es nochmal erneut!';
}


Schritt 5: Integration von MySQL und Einrichtung
Im letzten Schritt richten wir unsere Datenbank ein und verknüpfen die Datenbank mit unserem PHP Skript, denn aktuell ist es so, dass sich jeder immer noch einloggen kann und das wollen wir verhindern.

Wir gehen also in unser PHPmyAdmin und erstellen uns eine Datenbank, die ich in meinem Beispiel passwordhash nenne. Wenn wir die Datenbank erstellt haben, führen wir folgende MySQL Abfrage durch:

[quote]DROP TABLE IF EXISTS `accounts`;
CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(10) NOT NULL,
`user` varchar(64) NOT NULL,
`passwordhash` varchar(72) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

ALTER TABLE `accounts`
ADD PRIMARY KEY (`id`),
MODIFY `id` int(10) NOT NULL AUTO_INCREMENT;[/quote]
Nachdem wir unsere Tabelle in unsere Datenbank eingefügt haben, verbinden wir uns mit der Datenbank und lesen den abgefragten User aus.

<?php

$mysql 
= new MySQLi('localhost', 'BENUTZERNAME', 'PASSWORD', 'passwordhash');

if(
$mysql->connect_errno) {
    die(
$mysql->connect_error());
}

$user = $mysql->query('SELECT `passwordhash` FROM `accounts` WHERE `user` = \''. $_POST['username'] .'\' LIMIT 0,1');
$result = $user->fetch_assoc();


Nun haben wir in der Variable $result unsere Ergebnisse und können diese in unserer Password Überprüfung ersetzen. Danach sieht unser Code folgender maßen aus:
<?php

$mysql 
= new MySQLi('localhost', 'BENUTZERNAME', 'PASSWORD', 'passwordhash'); 

if(
$mysql->connect_errno) { 
    die(
$mysql->connect_error()); 
} 

$user = $mysql->query('SELECT `passwordhash` FROM `accounts` WHERE `user` = \''. $_POST['username'] .'\' LIMIT 0,1'); 
$result = $user->fetch_assoc();

if(
password_verify($_POST['password'], $result['passwordhash'])) { 
    if(
password_needs_rehash($result['passwordhash'], PASSWORD_BCRYPT, $options)) { 
        
// Neues Passwort speichern 
    
}
    
    echo 
'Das Passwort war korrekt. Hier geht es weiter!'; 
} else { 
    echo 
'Das Passwort war nicht korrekt. Versuche es nochmal erneut!'; 
}

Versuchen wir es doch mal. Wir erstellen uns einen Testaccount mit dem Namen test und dem Passwort test, wenn alles funktioniert habt ihr bis jetzt alles richtig gemacht.

Damit nun auch bei einer Aktualisierung unserer COST und unserer SALT der neue Wert in der Datenbank gespeichert wird, schreiben wir noch einen SQL Befehl, der unser Passwort aktualisieren soll, welches in die if-Anweisung von password_needs_rehash() gehört.

<?php
$new_hash 
= password_hash($_POST['password'], PASSWORD_BCRYPT, $options);
$update = $mysql->query('UPDATE `accounts` SET `passwordhash` = \''. $new_hash .'\' WHERE `user` = \''. $_POST['username'] .'\'');


Fertig ist unsere Login funktion und wir können uns nun Fehlerfrei anmelden.

Schritt 6: Ende, kompletter Code im Überblick
In diesem Schritt erkläre ich gar nichts, sondern gebe euch nochmal den kompletten Code in der Übersicht.

inc/password_compat.php
<?php
/**
 * A Compatibility library with PHP 5.5's simplified password hashing API.
 *
 * @author Anthony Ferrara <[email protected]>
 * @license http://www.opensource.org/licenses/mit-license.html MIT License
 * @copyright 2012 The Authors
 */
namespace {
    if (!
defined('PASSWORD_BCRYPT')) {
        
/**
         * PHPUnit Process isolation caches constants, but not function declarations.
         * So we need to check if the constants are defined separately from 
         * the functions to enable supporting process isolation in userland
         * code.
         */
        
define('PASSWORD_BCRYPT', 1);
        
define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
        
define('PASSWORD_BCRYPT_DEFAULT_COST', 10);
    }
    if (!
function_exists('password_hash')) {
        
/**
         * Hash the password using the specified algorithm
         *
         * @param string $password The password to hash
         * @param int    $algo     The algorithm to use (Defined by PASSWORD_* constants)
         * @param array  $options  The options for the algorithm to use
         *
         * @return string|false The hashed password, or false on error.
         */
        
function password_hash($password, $algo, array $options = array()) {
            if (!
function_exists('crypt')) {
                
trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
                return 
null;
            }
            if (
is_null($password) || is_int($password)) {
                
$password = (string) $password;
            }
            if (!
is_string($password)) {
                
trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
                return 
null;
            }
            if (!
is_int($algo)) {
                
trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
                return 
null;
            }
            
$resultLength = 0;
            switch (
$algo) {
                case 
PASSWORD_BCRYPT:
                    
$cost = PASSWORD_BCRYPT_DEFAULT_COST;
                    if (isset(
$options['cost'])) {
                        
$cost = $options['cost'];
                        if (
$cost < 4 || $cost > 31) {
                            
trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
                            return 
null;
                        }
                    }
                    
// The length of salt to generate
                    
$raw_salt_len = 16;
                    
// The length required in the final serialization
                    
$required_salt_len = 22;
                    
$hash_format = sprintf("$2y$%02d$", $cost);
                    
// The expected length of the final crypt() output
                    
$resultLength = 60;
                    break;
                default:
                    
trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
                    return 
null;
            }
            
$salt_req_encoding = false;
            if (isset(
$options['salt'])) {
                switch (
gettype($options['salt'])) {
                    case 
'NULL':
                    case 
'boolean':
                    case 
'integer':
                    case 
'double':
                    case 
'string':
                        
$salt = (string) $options['salt'];
                        break;
                    case 
'object':
                        if (
method_exists($options['salt'], '__tostring')) {
                            
$salt = (string) $options['salt'];
                            break;
                        }
                    case 
'array':
                    case 
'resource':
                    default:
                        
trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
                        return 
null;
                }
                if (
PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
                    
trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
                    return 
null;
                } elseif (
0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
                    
$salt_req_encoding = true;
                }
            } else {
                
$buffer = '';
                
$buffer_valid = false;
                if (
function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
                    
$buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
                    if (
$buffer) {
                        
$buffer_valid = true;
                    }
                }
                if (!
$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
                    
$buffer = openssl_random_pseudo_bytes($raw_salt_len);
                    if (
$buffer) {
                        
$buffer_valid = true;
                    }
                }
                if (!
$buffer_valid && @is_readable('/dev/urandom')) {
                    
$file = fopen('/dev/urandom', 'r');
                    
$read = PasswordCompat\binary\_strlen($buffer);
                    while (
$read < $raw_salt_len) {
                        
$buffer .= fread($file, $raw_salt_len - $read);
                        
$read = PasswordCompat\binary\_strlen($buffer);
                    }
                    
fclose($file);
                    if (
$read >= $raw_salt_len) {
                        
$buffer_valid = true;
                    }
                }
                if (!
$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
                    
$buffer_length = PasswordCompat\binary\_strlen($buffer);
                    for (
$i = 0; $i < $raw_salt_len; $i++) {
                        if (
$i < $buffer_length) {
                            
$buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
                        } else {
                            
$buffer .= chr(mt_rand(0, 255));
                        }
                    }
                }
                
$salt = $buffer;
                
$salt_req_encoding = true;
            }
            if (
$salt_req_encoding) {
                
// encode string with the Base64 variant used by crypt
                
$base64_digits =
                    
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
                
$bcrypt64_digits =
                    
'./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
                
$base64_string = base64_encode($salt);
                
$salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
            }
            
$salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
            
$hash = $hash_format . $salt;
            
$ret = crypt($password, $hash);
            if (!
is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
                return 
false;
            }
            return 
$ret;
        }
        
/**
         * Get information about the password hash. Returns an array of the information
         * that was used to generate the password hash.
         *
         * array(
         *    'algo' => 1,
         *    'algoName' => 'bcrypt',
         *    'options' => array(
         *        'cost' => PASSWORD_BCRYPT_DEFAULT_COST,
         *    ),
         * )
         *
         * @param string $hash The password hash to extract info from
         *
         * @return array The array of information about the hash.
         */
        
function password_get_info($hash) {
            
$return = array(
                
'algo' => 0,
                
'algoName' => 'unknown',
                
'options' => array(),
            );
            if (
PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
                
$return['algo'] = PASSWORD_BCRYPT;
                
$return['algoName'] = 'bcrypt';
                list(
$cost) = sscanf($hash, "$2y$%d$");
                
$return['options']['cost'] = $cost;
            }
            return 
$return;
        }
        
/**
         * Determine if the password hash needs to be rehashed according to the options provided
         *
         * If the answer is true, after validating the password using password_verify, rehash it.
         *
         * @param string $hash    The hash to test
         * @param int    $algo    The algorithm used for new password hashes
         * @param array  $options The options array passed to password_hash
         *
         * @return boolean True if the password needs to be rehashed.
         */
        
function password_needs_rehash($hash, $algo, array $options = array()) {
            
$info = password_get_info($hash);
            if (
$info['algo'] != $algo) {
                return 
true;
            }
            switch (
$algo) {
                case 
PASSWORD_BCRYPT:
                    
$cost = isset($options['cost']) ? $options['cost'] : PASSWORD_BCRYPT_DEFAULT_COST;
                    if (
$cost != $info['options']['cost']) {
                        return 
true;
                    }
                    break;
            }
            return 
false;
        }
        
/**
         * Verify a password against a hash using a timing attack resistant approach
         *
         * @param string $password The password to verify
         * @param string $hash     The hash to verify against
         *
         * @return boolean If the password matches the hash
         */
        
function password_verify($password, $hash) {
            if (!
function_exists('crypt')) {
                
trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
                return 
false;
            }
            
$ret = crypt($password, $hash);
            if (!
is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
                return 
false;
            }
            
$status = 0;
            for (
$i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
                
$status |= (ord($ret[$i]) ^ ord($hash[$i]));
            }
            return 
$status === 0;
        }
    }
}
namespace 
PasswordCompat\binary {
    if (!
function_exists('PasswordCompat\\binary\\_strlen')) {
        
/**
         * Count the number of bytes in a string
         *
         * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
         * In this case, strlen() will count the number of *characters* based on the internal encoding. A
         * sequence of bytes might be regarded as a single multibyte character.
         *
         * @param string $binary_string The input string
         *
         * @internal
         * @return int The number of bytes
         */
        
function _strlen($binary_string) {
            if (
function_exists('mb_strlen')) {
                return 
mb_strlen($binary_string, '8bit');
            }
            return 
strlen($binary_string);
        }
        
/**
         * Get a substring based on byte limits
         *
         * @see _strlen()
         *
         * @param string $binary_string The input string
         * @param int    $start
         * @param int    $length
         *
         * @internal
         * @return string The substring
         */
        
function _substr($binary_string, $start, $length) {
            if (
function_exists('mb_substr')) {
                return 
mb_substr($binary_string, $start, $length, '8bit');
            }
            return 
substr($binary_string, $start, $length);
        }
        
/**
         * Check if current PHP version is compatible with the library
         *
         * @return boolean the check result
         */
        
function check() {
            static 
$pass = NULL;
            if (
is_null($pass)) {
                if (
function_exists('crypt')) {
                    
$hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
                    
$test = crypt("password", $hash);
                    
$pass = $test == $hash;
                } else {
                    
$pass = false;
                }
            }
            return 
$pass;
        }
    }
}


index.html
<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8"> 
<title>Mein Loginsystem</title> 
</head> 
<body style="font-family:Arial, Helvetica, sans-serif;"> 
<div style="border-radius:40px;padding:40px;background:#CCC;width:366px;box-shadow:rgba(0,0,0,.1) 5px 5px 5px;height:120px;position:absolute;top:50%;left:50%;margin-top:-150px;margin-left:-173px;"> 
<form action="check.php" method="post"> 
<div style="height:30px;"> 
<label for="benutzer" style="display:inline-block;width:48%;font-size:18px;">Benutzername:</label> 
<input type="text" name="username" id="benutzer" style="height:10px;padding:5px;"> 
</div> 
<div style="height:45px;"> 
<label for="verifikation" style="display:inline-block;width:48%;font-size:18px;">Passwort:</label> 
<input type="password" name="password" id="verifikation" style="height:10px;padding:5px;"> 
</div>
<div style="height:30px;"> 
<input type="submit" value="Einloggen!" style="height:30px;width:100%;">
</div>
</form> 
</div> 
</body> 
</html>


costs.php
<?php 
/** 
 * This code will benchmark your server to determine how high of a cost you can 
 * afford. You want to set the highest cost that you can without slowing down 
 * you server too much. 8-10 is a good baseline, and more is good if your servers 
 * are fast enough. The code below aims for > 500 milliseconds stretching time, 
 * which is a good baseline for systems handling interactive logins. 
 */ 
$timeTarget = 0.5; // 500 milliseconds  

$cost = 4; 
do { 
    
$cost++; 
    
$start = microtime(true); 
    
password_hash('test', PASSWORD_BCRYPT, ['cost' => $cost, 'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)]); 
    
$end = microtime(true);
} while ((
$end - $start) < $timeTarget); 

echo 
'Appropriate Cost Found: ' . $cost;


check.php
<?php 
session_start
(); 

if((empty(
trim($_POST['username']))) 
    || (empty(
$_POST['password']))) { 
    exit(); 
} 

if ((
version_compare(PHP_VERSION, '5.3.7') >= 0)
     && (
version_compare(PHP_VERSION, '5.5.0') < 0)) {
    require_once(
dirname( __FILE__ ) . '/inc/password_compat.php'); 
} 

$options = array( 
    
'cost' => 13, 
    
'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM) 
); 

$mysql = new MySQLi('localhost', 'BENUTZERNAME', 'PASSWORD', 'passwordhash'); 

if(
$mysql->connect_errno) { 
    die(
$mysql->connect_error()); 
} 

$user = $mysql->query('SELECT `passwordhash` FROM `accounts` WHERE `user` = \''. $_POST['username'] .'\' LIMIT 0,1'); 
$result = $user->fetch_assoc();

if(
password_verify($_POST['password'], $result['passwordhash'])) { 
    if(
password_needs_rehash($result['passwordhash'], PASSWORD_BCRYPT, $options)) {
        
$new_hash = password_hash($_POST['password'], PASSWORD_BCRYPT, $options);
        
$update = $mysql->query('UPDATE `accounts` SET `passwordhash` = \''. $new_hash .'\' WHERE `user` = \''. $_POST['username'] .'\'');
    }
    
    echo 
'Das Passwort war korrekt. Hier geht es weiter!'; 
} else { 
    echo 
'Das Passwort war nicht korrekt. Versuche es nochmal erneut!'; 
}


Ich wünsche euch viel Spaß damit. Wir werden uns wiedersehen. Demnächst programmiere ich ein von mir geschaffenes Tool, perfekt geeignet für Anfänger 🙂

~ Bis dahin.

Du hast Tipps und Anregungen, was ich besser machen kann? Ich habe nehme jede konstruktive Kritik gerne an.

Kommentare

Autor Htaccess

Zurück zur Übersicht
Autor: Nils Reimers
Zurück: URLs im Text identifizieren

Für Fortgeschrittene

  • Objektorientierte Programmierung
  • PHP Sicherheit
  • Script-Beispiele
  • Codeschnipsel
  • Stellenmarkt
Mit freundlicher Unterstützung von:
  • Punkt191 Werbeagentur
  • CasinoAndy Finland
  • Casinoohnelizenz.info
  • Cryptocasinomaster.com
  • CasinoHEX.at
  • inkedin.com

Hoster – Geringste Ausfallzeit

  1. webgo Ø 1 Min.
  2. Linevast Ø 2 Min.
  3. netcup Ø 3 Min.
  4. All-Inkl.com Ø 6 Min.
  5. checkdomain Ø 8 Min.
  6. dogado Ø 17 Min.
  7. bplaced Ø 17 Min.
  8. Contabo Ø 25 Min.
  9. Hetzner Ø 49 Min.
  10. ONE.com Ø 62 Min.
» Mehr erfahren

Impressum | Datenschutz | Auf PHP-Einfach.de werben

© PHP-Einfach.de 2003 - 2023

Cookie-Zustimmung verwalten
Um dir ein optimales Erlebnis zu bieten, verwenden wir Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wenn du diesen Technologien zustimmst, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn du deine Zustimmung nicht erteilst oder zurückziehst, können bestimmte Merkmale und Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Anbieter verwalten Lese mehr über diese Zwecke
Einstellungen ansehen
{title} {title} {title}