How To Create A Simple Signup And Login System Using PHP And PDO

Added 6 months ago By Stephen Ilori

Tags

Creating A Simple Signup And Login System Using PHP And PDO

My name is Ilori Stephen, and I am a fullstack software developer in West Africa, Lagos Nigeria. In this article, I would be showing you how to Create a simple signup and login system using PHP and PDO.

Before we get started, I would like to talk about the requirements for this lecture and also share some knowledge about PDO.

Requirements

The following are the requirements that needs to be satisfied in order to get the best out of this lecture.

  1. A localhost server: You can download the latest version of any of LAMPP, MAMPP, XAMPP, WAMPP, AMPPS depending on your operating system in order to qucikly set and get a localhost server running on your machine.

  2. A text editor with a black theme installed: Any text editor should do fine but I recommend black.

  3. A Css framework: such as Bootstrap or MaterializeCss, it all depends on whichever Css framework you'd prefer, but for the sake of this lecture I recommend bootstrap.

  4. Basic knowledge of PHP.

  5. Download the mysql database from the github repository at Simple Signup And Login System With PHP And PDO.

With the requirements all satisfied, let's take some time to talk about PDO. Copied from the php.net website

The PHP Data Objects (PDO) extension defines a lightweight, consistent interface for accessing databases in PHP. Each database driver that implements the PDO interface can expose database-specific features as regular extension functions. Note that you cannot perform any database functions using the PDO extension by itself; you must use a database-specific PDO driver to access a database server.

PDO provides a data-access abstraction layer, which means that, regardless of which database you're using, you use the same functions to issue queries and fetch data. PDO does not provide a database abstraction; it doesn't rewrite SQL or emulate missing features. You should use a full-blown abstraction layer if you need that facility.

PDO ships with PHP 5.1, and is available as a PECL extension for PHP 5.0; PDO requires the new OO features in the core of PHP 5, and so will not run with earlier versions of PHP.

Back to the project, I believe it's time to get our hands dirty and write some codes </>. In your localhost htdocs directory or www directory, we would create a folder called login-and-signup-php but you can call the folder whatever you want.

Inside of our login-and-signup-php folder, we should have a working directory that looks like the following.

*/ login-and-signup-php (Parent Folder or Project)
    */ functions (Functions Folder) 
        /DB.PHP
        /Login.php
        /Signup.php
/-- Project's Root Dir
    /dashboard.php
    /login.php
    /register.php

Our login-and-signup-php contains a functions folder which contains the following files;

1. DB.php
2. Login.php
3. Signup.php

In the root directory of our login-and-signup-php, we have the following files;

1. dashboard.php
2. index.php
3. register.php

which all acts as our view files.

Editing Our Db.php (Functions Folder)

Our Db.php file in our login-and-signup-php funtions folder should contain the following.

    session_start();
  /**
   * This function creates a new database connection by creating a new PDO object which then returns the created database connection.
   * @param void | null
  **/
    function DbHandler ()
    {
        $dbHost = 'localhost';
        $dbName = 'YOUR_DATABASE_NAME';
        $dbUser = 'YOUR_MYSQL_USERNAME';
        $dbPass = 'YOUR_MYSQL_PASSWORD';

        //Create a DSN for the database resource...
        $Dsn = "mysql:host=" . $dbHost . ";dbname=" . $dbName;

        //Create an options configuration for the PDO connection...
        $options = array(
          PDO::ATTR_PERSISTENT => true,
          PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        );

        try {
          $Connection = new PDO($Dsn, $dbUser, $dbPass, $options);
          return $Connection;
        } catch (Exception $e) {
          var_dump ('Couldn\'t Establish A Database Connection. Due to the following reason: ' . $e->getMessage());
          exit;
        }
    }

In our DB.php file, we created a DBHandler function which creates some variables to store our environment or system configurations.

    /** dbHost. This is usually always localhost. **/
    $dbHost = 'localhost'; 
    /** dbName. The name of your database. **/
    $dbName = 'YOUR_DATABASE_NAME';
    /** dbUser. your MYSQL username **/
    $dbUser = 'YOUR_MYSQL_USERNAME'
    /** dbPass. your MYSQL password **/;
    $dbPass = 'YOUR_MYSQL_PASSWORD';

we also created a created a DSN to hold our database resource.

    $Dsn = "mysql:host=" . $dbHost . ";dbname=" . $dbName;

A DSN is short for a Data Source Name and it contains the information required to connect to the database. In general, a DSN consists of the PDO driver name, followed by a colon, followed by the PDO driver-specific connection syntax..

After our DSN was created, we created an Options Array which holds some sane defaults that serves as an extra configuration for the PDO Interface

    $options = array(
        PDO::ATTR_PERSISTENT => true,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    );
The PDO::ATTR_PERSISTENT option sets a persistent database connection rather than creating a new connection. This option actually goes easy on performance if you ask me.

The PDO::ATTR_ERRMODE option determines what happens when an error occurs. The PDO::ERRMODE_EXCEPTION value throws an exception when an error occurs. There are other values such as:

1. PDO::ERRMODE_SILENT which throws no exception, message or warning when an error occurrs. This is actually the default.

2. PDO::ERRMODE_WARNING which throws a PHP warning when an error occurrs.

You can read more on PDO Constants on the php.net website. After creating some extra configurations for our PDO Interface, we move on to create a new Instance of our PDO Object which attempts to create a new Database connection and returns the new Database connection if the operation succeeds else it dumps a descriptive or simple error message stating what broke during the operation.

    try {
        $Connection = new PDO($Dsn, $dbUser, $dbPass, $options);
        return $Connection;
    } catch (Exception $e) {
        return 'Couldn\'t Establish A Database Connection. Due to the following reason: ' . $e->getMessage();
    }

In order to verify everything is working fine, you can navigate your web browser to http://localhost/login-and-signup-php/functions/Db.php.

You should see a blank screen if the whole code in our Db.php works correctly. Else, you get a descriptive error message similar to the line below.

Couldn't Establish A Database Connection. Due to the following reason: WITH_SOME_EXTRA_PDO_MESSAGE

When you get this error, I would advise you check that the values passed here are exactly the ones from your environment or your system variable. Anything other than the "Couldn't Establish A Database Connection. Due to the following reason:" would probably be a syntax error. No offense though.

    /** dbName. The name of your database. **/
    $dbName = 'YOUR_DATABASE_NAME';
    /** dbUser. your MYSQL username **/
    $dbUser = 'YOUR_MYSQL_USERNAME'
    /** dbPass. your MYSQL password **/;
    $dbPass = 'YOUR_MYSQL_PASSWORD';

Editing Our Login.php (Functions Folder)

Our Login.php in our functions folder is where our application login business logic is kept. We have two functions in this file which accepts an array containing a valid Email Address And A Password to be matched with the saved Email address and Password in order to grant the user login access.

    require_once('./functions/Db.php');
  
  /**
   * @param Array $data
   * @return Array | void
   * Receives an email address and password from the $_POST superglobal and matches it against the databse records to authenticate the user
   */

  function Login(array $data)
  {
    $Data = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
    $Errors = [];
    $Email = stripcslashes(strip_tags($Data['email']));
    $Password = htmlspecialchars($Data['password']);

    //check if the email address exists in the database...
    $Email_check = checkEmail($Email);
    if (!$Email_check['status']) {
      $Errors['error'] = "Invalid credentials passed. Please, check the Email or Password and try again.";
      return $Errors;
    } else {
      //we check that the password matches the hash
      if (password_verify($Password, $Email_check['data']['password'])) {
        $_SESSION['current_session'] = [
          'status' => 1,
          'user' => $Email_check['data'],
          'date_time' => date('Y-m-d H:i:s'),
        ];
        header("Location: dashboard.php");
      }

      if (!password_verify($Password, $Email_check['data']['password'])) {
        $Errors['error'] = "Invalid credentials passed. Please, check the Email or Password and try again.";
        return $Errors;
      }
    }
  }

  /**
     * @param String $email
     * @return Array 
     * @desc Checks if an email string exists in the database and returns   an array which determines the output of the operation.
  */
  
  function checkEmail(string $email) : array
  {
    $dbHandler = DbHandler();
    $statement = $dbHandler->prepare("SELECT `first_name`, `last_name`, `email`, `password` FROM `user` WHERE `email` = :email");
    $statement->bindValue(':email', $email, PDO::PARAM_STR);
    $statement->execute();
    $result = $statement->fetch(PDO::FETCH_ASSOC);

    if (empty($result)) {
        $response['status'] = false;
        $response['data'] = [];
        return $response;
    }

    $response['status'] = true;
    $response['data'] = $result;
    return $response;
  }

Our Login.php in our functions folder depends on our Db.php which we created earlier.

    require_once('./functions/Db.php');

It does so because we would be making use of the database connection which was created in the DBHandler function in the Db.php file.

We have two functions in our Login.php file inside our functions folder. I would start by explaining the Login function. The Login function accepts an array as it's only parameter.

    function Login(array $data) { 
    /** Throws an exception if any Data type other than an array is passed as an arguement to this function. **/ 
    }

We then proceed to filter the values received from the passed array.

    $Data = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
    $Errors = [];

    $Email = stripcslashes(strip_tags($Data['email']));
    $Password = htmlspecialchars($Data['password']);
The filter_input_array is a built in php function that gets external variables, mostly PHP Superglobals and optionally filters them. It accepts 3 arguements ($type, $definition, $add_empty) but depending on your use case, only one is required.

In this section, we only need to worry about the first two arguement. Where we used the INPUT_POST i.e The data from our $_POST and the FILTER_SANITIZE_STRING which means we work the data and make sure that they are all valid strings.

We also filter the values from the array against any html tags and slashes in order to prevent Sql Injection.

We also convert any html special special characters in our password to their html entities equivalent by calling htmlspecialchars, another PHP built in function.

After validating the values from the array, we then check if the user exist by calling the checkEmail() function which accepts a string as it's only parameter and returns an array. We would get back to explain the process of the checkEmail function later.

    $Email_check = checkEmail($Email);
    if (!$Email_check['status']) {
      $Errors['error'] = "Invalid credentials passed. Please, check the Email or Password and try again.";
      return $Errors;
    } 

    if ($Email_check['status']) {
        if (password_verify($Password, $Email_check['data']['password'])) {
        $_SESSION['current_session'] = [
            'status' => 1,
            'user' => $Email_check['data'],
            'date_time' => date('Y-m-d H:i:s'),
        ];
        header("Location: dashboard.php");
      }

      if (!password_verify($Password, $Email_check['data']['password'])) {
        $Errors['error'] = "Invalid credentials passed. Please, check the Email or Password and try again.";
        return $Errors;
      }
    }
The checkEmail function returns an associative array which contains a status key which is either true when a user with that email exists or false when a user with the email can't be found.

When the status returns false, we end the execution of the function by returning an Errors Array which is later handled by our view.

When the status returns true, we then check if the user password retrieved from the application login form matches the hashed password in the database by using a special PHP input function called password_verify.

    password_verify($Password, $Email_check['data']['password'])

The password_verify function accepts two arguements which are both required and returns a boolean True if the given password which is the first arguement matches the given hash which is the second arguement. Else, the function returns a boolean False when the plain password does not match the hash.

Depending on the boolean value returned from the password verify, we determine whether to end the execution of the function and return the Errors array if the password_verify function evaluates to false. Else we make use of our $_SESSION superGlobals and create a current_session key which is set to an array containing the current application status, the current logged in user and the timestamp before performing an http Redirect to the dashboard.php.

    $_SESSION['current_session'] = [
        'status' => 1,
        'user' => $Email_check['data'],
        'date_time' => date('Y-m-d H:i:s'),
    ];
    header("Location: dashboard.php");

You can take your time to go through the Login function again and think of how you could refractor the function into something more.

There is more than one way to achieve a solution in programming.

I would like to explain the checkEmail function. This function takes an email String as it's only arguement and makes use of our DBHandler function from our Db.php file. It takes the Email which was passed as an arguement during it's function call and checks our database for a match in order to return an array containing a few information about the user and a Boolean true status if a user with the email is matched.

A Boolean false is returned and the user key in the returned array is empty.

    function checkEmail(string $email) : array
    {
        $dbHandler = DbHandler();
        $statement = $dbHandler->prepare("SELECT `first_name`, `last_name`, `email`, `password` FROM `user` WHERE `email` = :email");
        $statement->bindValue(':email', $email, PDO::PARAM_STR);
        $statement->execute();
        $result = $statement->fetch(PDO::FETCH_ASSOC);

        if (empty($result)) {
            $response['status'] = false;
            $response['data'] = [];
            return $response;
        }

        $response['status'] = true;
        $response['data'] = $result;
        return $response;
    }
    $dbHandler = DbHandler();
    $statement = $dbHandler->prepare("SELECT `first_name`, `last_name`, `email`, `password` FROM `user` WHERE `email` = :email");
    $statement->bindValue(':email', $email, PDO::PARAM_STR);
PDO has a few method which makes database operations easy, secure and takes an Object Oriented approach. 

The prepare method takes an SQL statement which can either be Named Parameters or positional paramters but in this case, we used the Named parameters, which is a placeholder in this form :column or :whatever-name-you-prefer.

The bindValue is also another PDO method which takes our placeholders from the generated prepared statement and replaces them with the right value. Which in our case is the Email passed as arguement. The bindValue also takes a third arguement which is the SQL Data Type.

The execute method then takes our PDO prepared statement, generates and executes a valid SQL statement.

The fetch method is also another PDO method, this method returns an associative array as it's default if no arguement is passed to the method, it's worth noting that the fetch method returns a single record.

You can read more on the various PDO Methods available on the php.net website.

    if (empty($result)) {
        $response['status'] = false;
        $response['data'] = [];
        return $response;
    }

    $response['status'] = true;
    $response['data'] = $result;
    return $response;
The result generated from the PDO operation is evaluated and an array is generated depending on the content of the previous PDO operation.

We will get back to using the functions created in our Login.php file when our login form is ready.

Editing Our Signup.php (Functions Folder)

Our Signup.php is where our application business logic for creating a new user is kept. we have three functions in this file, Signup, checkEmail and Register. This file also depends on our Db.php file which provides a DbHandler function which returns a DB connection.

I will explain the Signup and the Register function since the chekEmail function has been covered earlier in this chapter.

This style of programming is not really eficient as we are repeating or recreating the same function 'checkEmail' instead of reusing it. If this application grows into something larger maintaing it would be very difficult.

With that out of the way, our Signup.php file should contain the following.

    require_once('./functions/Db.php');

    /**
     * @param Array $data
     * @return Array 
     * @desc Receives an array conaining our user information in an attempt to create a new user.
    */

    function Signup(array $data) 
    {
        $Data = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
        
        //Registration Data Filtering....
        $first_name = stripcslashes(strip_tags($Data['first_name']));
        $last_name = stripcslashes(strip_tags($Data['last_name']));
        $email = stripcslashes(strip_tags($Data['email']));
        $password = htmlspecialchars($Data['password']);
        //Just In Case....
        $Errors = [];

        if (preg_match('/[^A-Za-z0-9_]/', $first_name)) {
            $Errors['first_name'] = "Sorry, Please enter a valid first name";
        }

        if (preg_match('/[^A-Za-z0-9_]/', $last_name)) {
            $Errors['last_name'] = "Sorry, Please enter a valid last name";
        }

        //Check if the email exists...
        $emailExists = checkEmail($email);
        if ($emailExists['status']) {
            $Errors['email'] = "Sorry, This email already exist.";
        }

        if (strlen($password) < 7) {
            $Errors['password'] = "Sorry, Use a stronger password";
        }

        if (count($Errors) > 0) {           
            $Errors['error'] = "Please, correct the Errors in your form in order to continue.";
            return $Errors;
        } else {
            //Create the new user...
            $Data = [
                'first_name' => $first_name,
                'last_name' => $last_name,
                'email' => $email,
                'password' => $password
            ];
            $registration = Register($Data);
            
            if ($registration) {
                //Before the redirect this would be a good time to send a mail or something in order to verify the user...
                array_pop($Data);
                $_SESSION['current_session'] = [
                    'status' => 1,
                    'user' => $Data,
                    'date_time' => date('Y-m-d H:i:s'),
                ];
                header("Location: dashboard.php");
            } else {
                //#You could probably notify the dev team within this line but this is just a demo still....
                $Errors['error'] = "Sorry an unexpected error and your account could not be created. Please try again later.";
                return $Errors;
            }
        }
    }

    /**
     * @param String $email
     * @return Array 
     * @desc Checks if an email string exists in the database and returns   an array which determines the output of the operation.
     */

    function checkEmail(string $email) : array
    {
        $dbHandler = DbHandler();
        $statement = $dbHandler->prepare("SELECT * FROM `user` WHERE `email` = :email");
        $statement->bindValue(':email', $email, PDO::PARAM_STR);
        $statement->execute();
        $result = $statement->fetch(PDO::FETCH_ASSOC);

        if (empty($result)) {
            $response['status'] = false;
            $response['data'] = [];
            return $response;
        }

        $response['status'] = true;
        $response['data'] = $result;
        return $response;
    }

    /**
     * @param Array $data
     * @return Array 
     * @desc Creates a new user and returns a boolean indicating the status of the              operation...
     */
    function Register(array $data)
    {
        $dbHandler = DbHandler();
        $statement = $dbHandler->prepare("INSERT INTO `user` (first_name, last_name, email, password, status, created_at, updated_at) VALUES (:first_name, :last_name, :email, :password, :status, :created_at, :updated_at)");
        
        //#Defaults....
        $timestamps = date('Y-m-d H:i:s');
        $status = 1;
        $password = password_hash($data['password'], PASSWORD_BCRYPT);
        //Values Bindings....
        $statement->bindValue(':first_name', $data['first_name'], PDO::PARAM_STR);
        $statement->bindValue(':last_name', $data['last_name'], PDO::PARAM_STR);
        $statement->bindValue(':email', $data['email'], PDO::PARAM_STR);
        $statement->bindValue(':password', $password, PDO::PARAM_STR);
        $statement->bindValue(':status', $status, PDO::PARAM_INT);
        $statement->bindValue(':created_at', $timestamps, PDO::PARAM_STR);
        $statement->bindValue(':updated_at', $timestamps, PDO::PARAM_STR);
        
        $result = $statement->execute();
        if ($result) {
            return true;
        } else {
            return false;
        }
    }
The Signup function takes an array as it's only parameter. The received array is then filtered and validated before calling the Register function which creates the new user and sets a new session for the user before an HTTP Redirect to the dashboard.php page. We also created the checkEmail function which helps in checking if the email address is available or not.
    function Signup(array $data) 
    {
        $Data = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
        
        //Registration Data Filtering....
        $first_name = stripcslashes(strip_tags($Data['first_name']));
        $last_name = stripcslashes(strip_tags($Data['last_name']));
        $email = stripcslashes(strip_tags($Data['email']));
        $password = htmlspecialchars($Data['password']);
        //Just In Case....
        $Errors = [];

        if (preg_match('/[^A-Za-z0-9_]/', $first_name)) {
            $Errors['first_name'] = "Sorry, Please enter a valid first name";
        }

        if (preg_match('/[^A-Za-z0-9_]/', $last_name)) {
            $Errors['last_name'] = "Sorry, Please enter a valid last name";
        }

        //Check if the email exists...
        $emailExists = checkEmail($email);
        if ($emailExists['status']) {
            $Errors['email'] = "Sorry, This email already exist.";
        }

        if (strlen($password) < 7) {
            $Errors['password'] = "Sorry, Use a stronger password";
        }

        if (count($Errors) > 0) {           
            $Errors['error'] = "Please, correct the Errors in your form in order to continue.";
            return $Errors;
        } else {
            //Create the new user...
            $Data = [
                'first_name' => $first_name,
                'last_name' => $last_name,
                'email' => $email,
                'password' => $password
            ];
            $registration = Register($Data);
            
            if ($registration) {
                //Before the redirect this would be a good time to send a mail or something in order to verify the user...
                array_pop($Data);
                $_SESSION['current_session'] = [
                    'status' => 1,
                    'user' => $Data,
                    'date_time' => date('Y-m-d H:i:s'),
                ];
                header("Location: dashboard.php");
            } else {
                //#You could probably notify the dev team within this line but this is just a demo still....
                $Errors['error'] = "Sorry an unexpected error and your account could not be created. Please try again later.";
                return $Errors;
            }
        }
    }

This is a very simple example, for a standard signup system, you would probably want to send an email to verify the user account. I would be creating another article next week which will show you how to create a standard signup system.

The Register function accepts an array as it's only arguement and creates a new user using our database connection made available from the DbHandler function in our Db.php file.
    function Register(array $data)
    {
        $dbHandler = DbHandler();
        $statement = $dbHandler->prepare("INSERT INTO `user` (first_name, last_name, email, password, status, created_at, updated_at) VALUES (:first_name, :last_name, :email, :password, :status, :created_at, :updated_at)");
        
        //#Defaults....
        $timestamps = date('Y-m-d H:i:s');
        $status = 1;
        $password = password_hash($data['password'], PASSWORD_BCRYPT);
        //Values Bindings....
        $statement->bindValue(':first_name', $data['first_name'], PDO::PARAM_STR);
        $statement->bindValue(':last_name', $data['last_name'], PDO::PARAM_STR);
        $statement->bindValue(':email', $data['email'], PDO::PARAM_STR);
        $statement->bindValue(':password', $password, PDO::PARAM_STR);
        $statement->bindValue(':status', $status, PDO::PARAM_INT);
        $statement->bindValue(':created_at', $timestamps, PDO::PARAM_STR);
        $statement->bindValue(':updated_at', $timestamps, PDO::PARAM_STR);
        
        $result = $statement->execute();
        if ($result) {
            return true;
        } else {
            return false;
        }
    }
The password_hash is another in-built PHP function which takes two parameters, a plain password and an hashing algorithm. The default resolves to PASSWORD_BCRYPT. 

PASSWORD_BCRYPT is used to create new password hashes using the CRYPT_BLOWFISH algorithm.

In the register function, we make use of the PDO prepare method which takes an Sql Statement with placeholders to prevent Sql Injection.

We also called the bindValue method on the generated PDO prepared statement which replaces our placeholders with the values from the $data array passed as a parameter.

We called the execute method which generates and executes the Sql generated from the PDO prepared statement.

The result of the execute method returns a boolean which is used in our Signup function in determining what process the script follows.

At this stage, all the files in our functions folder are ready to go, we only need to edit our view files and create the form required in creating a new user and authenticating an existing one.

Editing Our register.php (Root Dir)

Our register.php file should contain the following.

    <?php
        require_once('./functions/Signup.php');
        if (isset($_POST) && count($_POST) > 0) {
            $Response = Signup($_POST);
        }
    ?>
<!DOCTYPE html>
    <html lang="en-us">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Register</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    </head>
    <body>
        <div class="container mb-8">
         <div class="row center-align">
            <div class="col-xs-12 col-sm-12 col-md-12 col-xl-6 col-lg-6 col-xs-push-3 col-lg-push-3">
                <div class="card">
                    <div class="card-body">
                        <h3 class="card-title text-center mb-3">Signup</h3>
                        <?php if (isset($Response['error'])): ?>
                            <!-- Bootstrap Alert -->
                            <div class="alert alert-danger alert-dismissable mb-3"><b>Oops</b>, <?php echo $Response['error']; ?></div>
                            <!-- Bootstrap Alert -->
                        <?php endif; ?>
                        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
                            <div class="row">
                                <div class="col-xs-12 col-sm-12 col-lg-6 col-md-12 col-xl-6">
                                    <div class="form-group">
                                        <label for="">First Name</label>
                                        <input type="text" name="first_name" id="" class="form-control" required>
                                    </div>
                                    <?php if (isset($Response['first_name']) && !empty($Response['first_name'])): ?>
                                        <small class="alert alert-danger alert-dismissable"><?php echo $Response['first_name']; ?></small>
                                    <?php endif; ?>
                                </div>
                                <div class="col-xs-12 col-sm-12 col-lg-6 col-md-12 col-xl-6">
                                    <div class="form-group">
                                        <label for="">Last Name</label>
                                        <input type="text" name="last_name" id="" class="form-control" required>
                                    </div>
                                    <?php if (isset($Response['last_name']) && !empty($Response['last_name'])): ?>
                                        <small class="alert alert-danger alert-dismissable"><?php echo $Response['last_name']; ?></small>
                                    <?php endif; ?>
                                </div>
                            </div>
                            <div class="row">
                                 <div class="col-xs-12 col-sm-12 col-lg-6 col-md-12 col-xl-6">
                                    <div class="form-group">
                                        <label for="">Email</label>
                                        <input type="email" name="email" id="" class="form-control" required>
                                    </div>
                                    <?php if (isset($Response['email']) && !empty($Response['email'])): ?>
                                        <small class="alert alert-danger alert-dismissable"><?php echo $Response['email']; ?></small>
                                    <?php endif; ?>
                                </div>
                                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-6 col-xl-6">
                                    <div class="form-group">
                                        <label for="">Password</label>
                                        <input type="password" name="password" id="" class="form-control" required>
                                    </div>
                                    <?php if (isset($Response['password']) && !empty($Response['password'])): ?>
                                        <small class="alert alert-danger alert-dismissable"><?php echo $Response['password']; ?></small>
                                    <?php endif; ?>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
                                    <div class="form-group">
                                        <button type="submit" class="btn btn-success btn-block">Register</button>
                                    </div>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
         </div>
        </div>
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    </body>
</html>
    
At the very top of our register.php file, we created a PHP code island which requires our Signup.php from our functions folder and executes the function when the PHP superglobals $_POST is populated with data. The result of the function which is usually an array when an error or an execption occurs is passed to the $Response variable which we used in displaying specific error messages in our Html Form.
    require_once('./functions/Signup.php');
    if (isset($_POST) && count($_POST) > 0) {
        $Response = Signup($_POST);
    }

Editing Our login.php file (Root Dir)

Our register.php file should contain the following.

    <?php
        require_once('./functions/Login.php');
        if (isset($_POST) && count($_POST) > 0) {
            $Response = Login($_POST);
        }
    ?>
<!DOCTYPE html>
    <html lang="en-us">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Login</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    </head>
    <body>
        <div class="container mb-8">
         <div class="row center-align">
            <div class="col-xs-12 col-sm-12 col-md-12 col-xl-6 col-lg-6 col-xs-push-3 col-lg-push-3">
                <div class="card">
                    <div class="card-body">
                        <h3 class="card-title text-center mb-3">Login</h3>
                        <?php if (isset($Response['error'])): ?>
                            <!-- Bootstrap Alert -->
                            <div class="alert alert-danger alert-dismissable mb-3"><b>Oops</b>, <?php echo $Response['error']; ?></div>
                            <!-- Bootstrap Alert -->
                        <?php endif; ?>
                        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
                            <div class="row">
                                <div class="col-xs-12 col-sm-12 col-lg-12 col-md-12 col-xl-12">
                                    <div class="form-group">
                                        <label for="">Email Address</label>
                                        <input type="email" name="email" id="" class="form-control" required>
                                    </div>
                                </div>
                                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
                                    <div class="form-group">
                                        <label for="">Password</label>
                                        <input type="password" name="password" id="" class="form-control" required>
                                    </div>
                                </div>
                                <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
                                    <div class="form-group">
                                        <button type="submit" class="btn btn-success btn-block">Login</button>
                                    </div>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
         </div>
        </div>
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    </body>
</html>

At the very top of our login.php file, we created a PHP code island which requires our Login.php from our functions folder and executes the function when the PHP superglobals $_POST is populated with data. The result of the function which is usually an array when an error or an execption occurs is passed to the $Response variable which we used in displaying specific error messages in our Html Form.
    require_once('./functions/Login.php');
    if (isset($_POST) && count($_POST) > 0) {
        $Response = Signup($_POST);
    }

Editing Our Dashboard.php (Root Dir)

Our dashboard.php file should contain the following.

    <?php session_start(); ?>
    <?php if (!isset($_SESSION['current_session'])) header('Location: login.php'); ?>
<!DOCTYPE html>
<html lang="en-us">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Dashboard | <?php echo $_SESSION['current_session']['user']['last_name'] . ' ' . $_SESSION['current_session']['user']['first_name']; ?></title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
    <div class="container mb-8">
        <div class="row center-align">
            <div class="col-xs-12 col-sm-12 col-md-12 col-xl-12 col-lg-12">
                <div class="jumbotron">                
                    <p class="mb-4">Dashboard</p>
                    <hr>
                    <p>Welcome back <?php echo $_SESSION['current_session']['user']['last_name'] . ' ' . $_SESSION['current_session']['user']['first_name']; ?></p>
                    <span>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Illum quia rem quisquam, nulla quibusdam voluptatibus commodi? Omnis quia quo eligendi odio modi accusantium nihil, commodi laudantium adipisci ex pariatur minus explicabo, ipsum consequatur fugit magni inventore obcaecati nesciunt recusandae quibusdam?</span>
                </div>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>

At the very top of our dashboard.php, we have two PHP code island which initializes a new session and performs an http redirect if the current_session key has not been set in the PHP $_SESSION superglobals. 

This is a very simple example which shows how easy creating a login an signup system can get. You shouldn't limit yourself to this example. What I would want you to do next is to improvise and come up with something better than this example. Like I metioned earlier,

There is more than one way to achieve a solution in programming.

So I have prepared two challenges which would at least make this application look better and feel a little closer to a real world example. I would like you to do the following;

  1. Perform an HTTP Redirect if a logged in or authenticated user visits the login.php and the register.php page.

  2. Create a log out action.

These are very simple examples and I trust you can achieve them.

You can follow me on twitter @Stephen Ilori and send me a message if you have any questions or you run into any problems with this lecture.

You can also reach me on linkedin @Stephen Ilori if you have any Job Oferrings or questions.

You can follow me on github @Harry Wonder.

You can also clone this project on github @Simple Login And Signup System Using PHP And PDO.

Don't forget to upvote. Thank you for reading. Ilori Stepen A.

How To Create A Simple Signup And Login System Using PHP And PDO was Authored by Stephen Ilori
Get to know more about Stephen Ilori
Author's Avatar

Stephen Ilori

I am a fullstack web developer in Lagos igeria with 1 + year working experience. I enjoy building software applications for both myself and my firm.

See All Stephen Ilori Articles

All Tags

If you are looking for more, browse through our available tags.

Frontend Backend Fullstack Devops Mobile Career
1
423
1

Subscribe To Our Newsletter

Subscribe to our newsletter... Get weekly helpful tips on programming and video updates... We promise never to bug you. Just about two to three messages per week.