A very secure procedural MySQLI login script against injections I know there are other ways to create a login script like Object Oriented, Prepared Statements and PDO, but how about those old MySQL PHP users like me trying to change from old style to the new ways? Here is a login script code I created for those like me changing from MySQL to MySQLI the easy way.

Please take a look at the follow code and help us improve it, make it shorter, give us ideas, review is the symbols used are safe or not. How about adding brute force check so users can only fail to login 3 times per hour?

session_start();
include 'database/connection.php';
// we clean username against sql injection
$username=mysqli_real_escape_string($database,$_POST['form_user']);
// we clean password against sql injection
$password=mysqli_real_escape_string($database,$_POST['form_password']);
// if we get empty username and password we redirect to error page
if (empty($username) || empty($password)){header('Location: index.php?error=1');exit();}
// we clean username and password against XS injection, 0 to 9 and a to z and A to Z only allowed or we redirect to error page
if (preg_match("/[^A-Za-z0-9]/", $username)){header('Location: index.php?error=2');exit();}
if (preg_match("/[^A-Za-z0-9]/", $password)){header('Location: index.php?error=3');exit();}
// now we check if user exist 
$members="SELECT * FROM `accounts` WHERE `member` = '$username'";
$result=mysqli_query($database,$members);
// if user exist we redirect to error page
if(mysqli_num_rows($result)==0){header('Location: index.php?error=4');exit;}
// we will now check if salted password is correct
$user=mysqli_fetch_array($result,MYSQL_ASSOC);
// encoding method
$encoding=hash('sha256',$user['codificacion'].hash('sha256',$password));
// if password is not correct we redirect to error page
if($encoding!=$user['password']){header('Location: index.php?error=5');exit;}
// now everything is ok so we should set session, the session name will be member username
$_SESSION['username']=$user['member'];
// because we have admins, mods and users we need to check user privilege and redirect
if ($user['privilege']=="USER"){header('Location: users/index.php');exit();}
else if($user['privilege']=="ADMIN"){header('Location: admins/index.php');exit();}
else if($user['privilege']=="MOD"){header('Location: mods/index.php');exit();}
// if user is not admin or user or mod there must be something wrong so we kick them
else {header('Location: kick.php?error=6');exit();}
You're not checking whether $_POST[..] exists at all or whether any data has been submitted via POST, this may cause Undefined index notices.
You're not supposed to use empty on variables that you're explicitly declaring. empty is shorthand for !isset($var) || !$var. Since your variables are guaranteed to be set (you define them in the previous two lines), no need to suppress error reporting here with empty.
You don't need to clean a username or password against any sort of injection. Injection issues must be mitigated by properly escaping data in the right context, not by restricting the allowed characters used. If you have a specific business rule for restricting allowed characters so be it, but injection prevention is not it.
You're MySQL-escaping the values before you're checking for their validity. You need to do that in the opposite order. Escaping is always the last thing you do. There's no real issue in this case, since you're not modifying the string after escaping and your validity check isn't influenced either; but you should still stick to that rule.
You're using an inadequate password hash. Use password_hash instead.
You could be using a switch instead of the if..else chain.
You really should be using prepared statements to avoid escaping altogether. I know you're trying to take it slow, but you (should) have to make that move eventually, so why not now?


You may want to read:


The Great Escapism (Or: What You Need To Know To Work With Text Within Text)
The Definitive Guide To PHP's isset And empty


In summary, I'd write it like this (using procedural style for your benefit):

if (!isset($_POST['form_user'], $_POST['form_password'])) {
    header('Location: index.php?error=1');
    exit;
}

session_start();
include 'database/connection.php';

$stmt = mysqli_prepare($database, 'SELECT * FROM `accounts` WHERE `member` = ?');
mysqli_stmt_bind_param($stmt, 's', $_POST['form_user']);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$user = mysqli_fetch_assoc($result);

if (!$user) {
    header('Location: index.php?error=4');
    exit;
}

if (!password_verify($_POST['form_password'], $user['password'])) {
    header('Location: index.php?error=5');
    exit;
}

$_SESSION['username'] = $user['member'];

switch ($user['privilege']) {
    case 'USER':
        header('Location: users/index.php');
        exit;
    case 'ADMIN': 
        header('Location: admins/index.php');
        exit;
    case 'MOD': 
        header('Location: mods/index.php');
        exit;
    default:
        header('Location: kick.php?error=6');
        exit;
}