0

I'm trying to perform a form register validation but I don't know if I'm doing it right.

First I'm storing an error message for each blank field in my form. After that if my fields aren't empty I want to validate the username field (from having invalid characters), password and email

The problem is when I delete the die(); line in my username validation conditional, it does show me both the error message and the succes message and the invalid username is inserted in my database.

I'm pretty sure the problem is in my if($numrows==0) conditional but I can't figure it out why.

<?php
session_start();
$con=mysql_connect('localhost','root','') or die(mysql_error());
mysql_select_db('user_registration') or die("cannot select DB");


if(isset($_POST["submit"])){

    $arrErrors = array();
    unset($_SESSION['errors']);

    if($_POST['user'] == ''){
        $arrErrors['user_not_completed'] = "Username is not completed!";
        $_SESSION['errors'] = $arrErrors;
        header("Location: register.php");
    }

    if($_POST['pass'] == ''){
        $arrErrors['pass_not_completed'] = "Password is not completed!";
        $_SESSION['errors'] = $arrErrors;
        header("Location: register.php");
    }

    if($_POST['email'] == ''){
        $arrErrors['email_not_completed'] = "Email is not completed!";
        $_SESSION['errors'] = $arrErrors;
        header("Location: register.php");
    }

    if(!empty($_POST['user']) && !empty($_POST['pass']) && !empty($_POST['email'])) {
        $user=$_POST['user'];
        $pass=$_POST['pass'];
        $email=$_POST['email'];

            if(!preg_match("/^[a-zA-Z'-]+$/",$user)) {
                $arrErrors['invalid_user'] = "Username is invalid!";
                $_SESSION['errors'] = $arrErrors;
                header("Location: register.php");
                die();
            } 

        $query=mysql_query("SELECT * FROM users WHERE username='".$user."'");
        $numrows=mysql_num_rows($query);


        if($numrows==0){
            $sql="INSERT INTO users(username,password, email) VALUES('$user','$pass', '$email')";
            $result=mysql_query($sql);


            if($result){
                $arrErrors['succes'] = 'Account successfuly created!';
                $_SESSION['errors'] = $arrErrors;
                header("Location: register.php");
            } 

        } else {
            $arrErrors['already_exists'] = 'That username already exists!';
            $_SESSION['errors'] = $arrErrors;
            header("Location: register.php");
        }

} 

}
?>
Sergiu Turus
  • 27
  • 1
  • 1
  • 8
  • [Little Bobby](http://bobby-tables.com/) says [your script is at risk for SQL Injection Attacks.](http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php). Even [escaping the string](http://stackoverflow.com/questions/5741187/sql-injection-that-gets-around-mysql-real-escape-string) is not safe! – Jay Blanchard Apr 29 '16 at 13:06
  • Please [stop using `mysql_*` functions](http://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php). [These extensions](http://php.net/manual/en/migration70.removed-exts-sapis.php) have been removed in PHP 7. Learn about [prepared](http://en.wikipedia.org/wiki/Prepared_statement) statements for [PDO](http://php.net/manual/en/pdo.prepared-statements.php) and [MySQLi](http://php.net/manual/en/mysqli.quickstart.prepared-statements.php) and consider using PDO, [it's really pretty easy](http://jayblanchard.net/demystifying_php_pdo.html). – Jay Blanchard Apr 29 '16 at 13:06
  • Please use PHP's [built-in functions](http://jayblanchard.net/proper_password_hashing_with_PHP.html) to handle password security. If you're using a PHP version less than 5.5 you can use the `password_hash()` [compatibility pack](https://github.com/ircmaxell/password_compat). Make sure that you [don't escape passwords](http://stackoverflow.com/q/36628418/1011527) or use any other cleansing mechanism on them before hashing. Doing so *changes* the password and causes unnecessary additional coding. – Jay Blanchard Apr 29 '16 at 13:06
  • 1
    You should use `exit()` after a header, not `die()`. – Jay Blanchard Apr 29 '16 at 13:08
  • Beside the valid points Jay raised, if you remove the `die()` statement, the code happily continues running, because setting the "Location" header does not terminate the script. Because the invalid username is probably unique in your database, the number of rows returned is 0 and the invalid user will be inserted. – Pieter van den Ham Apr 29 '16 at 13:24

1 Answers1

1

Here's what I'd suggest you do:

<?php
    //FIRST I WOULD CHECK IF SESSION EXIST BEFORE STARTING IT:
    if (session_status() == PHP_SESSION_NONE  || session_id() == '') {
        session_start();
    }
    //NEXT I'D USE PDO AS MY DATABASE ABSTRACTION LAYER: IT HAS A LOT OF ADVANTAGES, REALLY:
    //DATABASE CONNECTION CONFIGURATION:
    defined("HOST")     or define("HOST",   "localhost");           //REPLACE WITH YOUR DB-HOST
    defined("DBASE")    or define("DBASE",  "user_registration");   //REPLACE WITH YOUR DB NAME
    defined("USER")     or define("USER",   "root");                //REPLACE WITH YOUR DB-USER
    defined("PASS")     or define("PASS",   "");                    //REPLACE WITH YOUR DB-PASS

    if(isset($_POST["submit"])){
        //THEN CLEAN UP THE SUBMITTED DATA TO AVOID POSSIBLE ATTACKS...
        $user       = isset($_POST['user'])     ? htmlspecialchars(trim($_POST['user']))    : null;     //PROTECT AGAINST ATTACKS
        $pass       = isset($_POST['pass'])     ? htmlspecialchars(trim($_POST['pass']))    : null;     //PROTECT AGAINST ATTACKS
        $email      = isset($_POST['email'])    ? htmlspecialchars(trim($_POST['email']))   : null;     //PROTECT AGAINST ATTACKS
        $passRX     = '#(^[a-zA-z0-9\-\+_\}\{\(\)])([\w\.\-\\:\;\+\(\)\/\}\{\(\)\ ])*\w*$#';
        $userRX     = '#(^[a-zA-z])([\w\.\-\(\)\ ])*\w*$#';
        $arrErrors  = array();

        unset($_SESSION['errors']);

        //CHECK IF USERNAME CONFORMS TO THE CUSTOM USERNAME REG-EXP...
        if(!preg_match($userRX, $user)){
            $arrErrors['user_not_completed'] = "Username is either not completed or is invalid!";
            //SAVE ERRORS TO SESSION
            $_SESSION['errors'] = $arrErrors;
            //REDIRECT BACK TO REGISTER PAGE
            header("Location: register.php");
            exit;
        }

        //CHECK IF PASSWORD CONFORMS TO THE CUSTOM PASSWORD REG-EXP...
        if(!preg_match($passRX, $pass)){
            $arrErrors['pass_not_completed'] = "Password is not completed!";
            //SAVE ERRORS TO SESSION
            $_SESSION['errors'] = $arrErrors;
            //REDIRECT BACK TO REGISTER PAGE
            header("Location: register.php");
            exit;
        }

        //CHECK IF E-MAIL CONFORMS TO THE STANDARD E-MAIL FORMAT USING BUILT-FUNCTIONS...
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $arrErrors['email_not_completed'] = "Email is not completed!";
            //SAVE ERRORS TO SESSION
            $_SESSION['errors'] = $arrErrors;
            //REDIRECT BACK TO REGISTER PAGE
            header("Location: register.php");
            exit;
        }

        //BECAUSE WE HAVE SANITIZED VERSIONS OF OUR $user, $pass & $email VARIABLES
        //WE CAN JUST  USE THEM DIRECTLY HERE:
        if($user && $pass && $email) {
            //HERE WE BEGIN THE PDO HIGH-LEVEL MAGIC... ;-)
            try {
                $dbh        = new PDO('mysql:host='.HOST.';dbname='. DBASE,USER,PASS);
                $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                $stmt       = $dbh->prepare("SELECT * FROM users WHERE username = :user");
                $stmt->execute(['user' => $user]);
                $objUser    = $stmt->fetch(PDO::FETCH_OBJ);

                //THIS USER DOES NOT ALREADY EXIST SO WE GO AHEAD AND CREATE A CORRESPONDING RECORD IN THE DB TABLE
                if(!$objUser){
                    $stmt   = $dbh->prepare("INSERT INTO users (username, password, email) VALUES(:user, :pass, :email)");
                    $stmt->bindParam(':user',   $user);
                    $stmt->bindParam(':pass',   $pass);
                    $stmt->bindParam(':email',  $email);
                    $insertStatus   = $stmt->execute();

                    if($insertStatus){
                        $arrErrors['succes']    = 'Account successfuly created!';
                        $_SESSION['errors']     = $arrErrors;
                        header("Location: register.php");
                        exit;
                    }
                }else {
                    $arrErrors['already_exists']    = 'That username already exists!';
                    $_SESSION['errors']             = $arrErrors;
                    header("Location: register.php");
                    exit;
                }


                //GARBAGE COLLECTION
                $dbh        = null;
            }catch(PDOException $e){
                //YOU HANDLE YOUR EXCEPTIONS HERE IN YOUR OWN UNIQUE MANNER...
                echo $e->getMessage();
            }
        }

    }
?>

Hope this helps a bit...

Poiz
  • 7,611
  • 2
  • 15
  • 17