Create a Signup and Login System with PHP and MySQL

Last Updated on Nov 14, 2023

login-page

Learning website backend development will make you realize that almost every system needs a signup and login feature. If this is your first time creating one or you forgot how to create it, then this tutorial is for you.

In this tutorial, we will create a signup/registration and login system using HTML, Bootstrap, PHP and MySQL. Instead of Bootstrap, you can use CSS for styling the HTML.

How does our signup and login system works

First, we have our homepage (index.php). On our homepage, we will show a login and signup buttons if the user is not logged in; otherwise, we will show our homepage content, which, for the sake of this tutorial, will only output their name, email, and a logout button that will enable them to logout. The login and signup buttons will go to their respective pages when clicked.

On the signup page, a user can create an account by providing a name, email, and password. On the login page, a user can log in using their email and password.

Now that we know how our signup and login system will work, let's proceed to creating it.

  1. Create the neccessary files

    First things first, let's prepare the files that we will need in this tutorial. In the folder that you will be working on, create the following files: index.php, login.php, signup.php, check-login.php, connect.php, and logout.php. In addition, create a folder named php-actions, and in that folder, create the following files: login.php and signup.php.

    The index.php, as you may already know, is our homepage. The login.php and signup.php files in our root directory will be our login and signup forms. On the other hand, the login.php and signup.php files under the php-actions directory are the files to which the forms will be sent.

    The logout.php, as you may guess, is the file that is responsible for logging out the user. The connect.php will contain our database configuration, and finally, the check-login.php is the file that will redirect the user to the homepage if the user wants to access the login and signup page when he or she is logged in.

  2. Run the following SQL code either in the phpMyAdmin in SQL tab or on the MySQL Command Line Client.

    CREATE DATABASE signup_login;
    
    use signup_login;
    
    CREATE TABLE user (
      user_id int(11) NOT NULL AUTO_INCREMENT,
      fullname varchar(100) NOT NULL,
      email varchar(255) NOT NULL,
      password varchar(255) NOT NULL,
      PRIMARY KEY (user_id),
      UNIQUE(email)
    );
    
  3. Connect the Database

    Type the following code in connect.php.

    <?php
    $host = 'localhost';
    $dbname = 'signup_login';
    $user = 'root';
    $password = '';
    
    $database = new PDO("mysql:host={$host};dbname={$dbname}", $user, $password);
    

    When connecting to your database, make sure you have the correct configuration based on your MySQL server.

  4. Create the homepage

    Now type the following code inside index.php:

    <?php session_start(); ?>
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
        <title>Homepage</title>
      </head>
      <body class="container m-3">
        <?php if(empty($_SESSION['USER_INFORMATION'])): ?>
          <a href="login.php" class="btn btn-primary h5 fw-bold">Login</a>
    	  <a href="signup.php" class="btn btn-success h5 fw-bold">Signup</a>
        <?php else: ?>
          <p>Fullname: <?php echo htmlspecialchars($_SESSION['USER_INFORMATION']['FULLNAME']); ?></p>
          <p>Email: <?php echo htmlspecialchars($_SESSION['USER_INFORMATION']['EMAIL']); ?></p>
          <a href="logout.php" class="btn btn-danger h5 fw-bold">Logout</a>
        <?php endif; ?>    
      </body>
    </html>
    

    In our code above, we have used an if else statement to check if the $_SESSION['USER_INFORMATION'] is empty or not. In that way, we will know if the user is logged in or not.

    The $_SESSION['USER_INFORMATION'] will be created when the user logs in; later, we will do this in php-actions/login.php.

  5. Create the signup form

    Now let's implement our signup feature. Let's start with signup form, type the following code inside signup.php under the root directory:

    <?php 
    session_start();
    require_once 'check-login.php';
    require_once 'php-actions/signup.php';
    ?>
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
        <title>Signup</title>
      </head>
      <body class="bg-dark">
        <main class="container-fluid">
          <div class="row justify-content-center">
            <div class="col-md-6 card mt-5">
              <div class="card-body">
                <div class="py-2">
                  <h1>Sign up</h1>
                </div>
                <?php echo $message; ?>
                <form class="form-row" method="post">
                  <div class="col py-2">
                    <label class="fw-bold" for="fullname">Fullname</label>
                    <input class="form-control" type="text" name="fullname" id="fullname"
                    value = "<?php echo empty($_POST['fullname']) ? '' : $_POST['fullname'] ?>" required>
                  </div>
                  <div class="col py-2">
                    <label class="fw-bold" for="email">Email</label>
                    <input class="form-control" type="email" name="email" id="email"
                    value = "<?php echo empty($_POST['email']) ? '' : $_POST['email'] ?>" required>
                  </div>
                  <div class="col py-2">
                    <label class="fw-bold" for="password">Password</label>
                    <input class="form-control" type="password" name="password" id="password" required>
                  </div>
                  <div class="col py-2">
                    <label class="fw-bold" for="confirm-password">Confirm password</label>
                    <input class="form-control" type="password" name="confirm-password" id="confirm-password" required>
                  </div>
                  <div class="col py-2">
                    <input class="btn btn-primary w-100"type="submit" value="Sign up" name="signup">
                  </div>
                </form>
                <div class="text-center py-2">
                  <span>Already have an account?</span>
                  <a class="link-underline link-underline-opacity-0 link-underline-opacity-75-hover" href="login.php">Log in</a>
                </div>
              </div>
            </div>
          </div>
        </main>
      </body>
    </html>
    

    In our above code, we echo the $message variable, which is supposedly created in our php-actions/signup.php, so if you run the code, there might be a warning, but don't worry; it will go away once we get to the next section.

    When the user signs up and there is an error, we don't want them to re-enter everything, so we set the value attribute to PHP ternary operators such as <?php echo empty($_POST['fullname']) ? '' : $_POST['fullname'] ?>. We did that for fullname and email inputs, but not for passwords. That is because passwords are sensitive data and the passwords are masked, so the user might already have forgotten them.

    Later, when testing, it would be best to temporarily remove the required attribute and change the type attribute from email to text attribute of inputs so you can test the form validation of PHP.

  6. Create the signup action

    Now let's make our signup feature works. Type the following code inside signup.php under the php-actions directory.

    <?php
    require_once 'connect.php';
    $message = '';
    if(!empty($_POST['signup'])) {
      signup();
    }
    
    function signup() {
      global $message, $database;
      
      if(!validate_account()) {
        return;
      }
    
      $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
      $statement = $database->prepare("INSERT INTO user (fullname, email, password) 
      VALUES (:fullname, :email, :password) ");
      $statement->bindParam(':fullname', $_POST['fullname']);
      $statement->bindParam(':email', $_POST['email']);
      $statement->bindParam(':password', $password);
      if(!$statement->execute()) {
        $message = "<div class='alert alert-danger'>Sign up Failed. Please try again.</div>";
        return;
      }
      $message = "<div class='alert alert-success'>Sign up Successful. You can now login</div>";
    }
    
    function validate_account() {
      global $message, $database;
      if(empty($_POST['fullname'])) {
        $message = "<div class='alert alert-danger'>Please enter your name</div>";
        return false;
      }
      if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
        $message = "<div class='alert alert-danger'>Please enter valid email</div>";
        return false;
      }
      $statement = $database->prepare("SELECT COUNT(user_id) FROM user WHERE email = :email");
      $statement->bindParam(':email', $_POST['email']);
      $statement->execute();
      $result = $statement->fetch(PDO::FETCH_BOTH)[0];
      if($result >= 1) {
        $message = "<div class='alert alert-danger'>Email already exist.</div>";
        return false;
      }
      if(empty($_POST['password'])) {
        $message = "<div class='alert alert-danger'>Please enter your password</div>";
        return false;
      }
      if(strlen($_POST['password']) < 8) {
        $message = "<div class='alert alert-danger'>Password should be atleast 8 characters</div>";
        return false;
      }
      if($_POST['password'] != $_POST['confirm-password'] ) {
        $message = "<div class='alert alert-danger'>Passwords do not match</div>";
        return false;
      }
      return true;
    }
    

    In our code above, we created two functions: validate_account() and signup().

    The validate_account() function determines if all the inputs are valid; it returns true if valid, otherwise false. First, it checks if the fullname is not empty by using the empty() function, then it validates the email by using the filter_var() function; after that, it queries the database to see if the email exists in the database; then it checks if the password is not empty, again by using the empty() function; after that, it checks if the length of the password is at least 8 characters by using the strlen() function; finally, it checks if the password and confirm password are the same.

    The signup() function, on the other hand, inserts the user data into the database if it passes the validation. First, it validates the inputs by using the validate_account() function, which we created in the same file; then, it hashes the password using the password_hash() function; and finally, it inserts the data into the database.

    If you refresh the signup page, the warning should be gone now and submitting the form should work now.

  7. Create the login form

    Now that we have the signup feature, let's add the login feature. Start with our login form: type the following inside login.php under the root directory.

    <?php
    session_start();
    require_once 'check-login.php';
    require_once 'php-actions/login.php';
    ?>
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
        <title>Login</title>
      </head>
      <body class="bg-dark">
        <main class="container-fluid">
          <div class="row justify-content-center">
            <div class="col-md-6 card mt-5">
              <div class="card-body">
                <div class="py-2">
                  <h1>Log in</h1>
                </div>
                <?php echo $message; ?>
                <form class="form-row" method="post">
                  <div class="col py-2">
                    <label class="fw-bold" for="email">Email</label>
                    <input class="form-control" type="email" name="email" id="email"
                    value = "<?php echo empty($_POST['email']) ? '' : $_POST['email'] ?>" required>
                  </div>
                  <div class="col py-2">
                    <label class="fw-bold" for="password">Password</label>
                    <input class="form-control" type="password" name="password" id="password" required>
                  </div>
                  <div class="col py-2">
                    <a href="#0" class="link-underline link-underline-opacity-0 link-underline-opacity-75-hover">Forgot Password?</a>
                  </div>
                  <div class="col py-2">
                    <input class="btn btn-primary w-100" type="submit" value="Log in" name="login">
                  </div>
                </form>
                <div class="text-center py-2">
                  <span>No account yet?</span>
                  <a class="link-underline link-underline-opacity-0 link-underline-opacity-75-hover" href="signup.php" >Sign up</a>
                </div>
              </div>
            </div>
          </div>
        </main>
      </body>
    </html>
    

    Pretty much everything we did in our signup form is also in our login form above. Including the warning due to the $message variable and the PHP ternary operator.

  8. Create the login action

    To complete our login feature, let's add our login action. Type the following code inside login.php under the php-actions directory:

    <?php
    require_once 'connect.php';
    $message = '';
    if(!empty($_POST['login'])) {
      login();
    }
    
    function login() {
      global $message, $database;
      
      $statement = $database->prepare("SELECT COUNT(user_id) as total, password, fullname, email, 
      user_id FROM user WHERE email = :email LIMIT 1");
      $statement->bindParam(":email", $_POST['email']);
      $statement->execute();
      $result = $statement->fetch(PDO::FETCH_ASSOC);
      if($result['total'] < 1) {
        $message = "<div class='alert alert-danger'>Email or Password is incorrect.</div>";
        return;
      }
      if(!password_verify($_POST['password'], $result['password'])) {
        $message = "<div class='alert alert-danger'>Email or Password is incorrect.</div>";
        return;
      }
      $_SESSION['USER_INFORMATION']['ID'] = $result['user_id'];
      $_SESSION['USER_INFORMATION']['FULLNAME'] = $result['fullname'];
      $_SESSION['USER_INFORMATION']['EMAIL'] = $result['email'];
      
      header('Location: ./');
      die();
    }
    

    Similar to our signup action, we have the login() function in the code above.

    The login() function checks if the email and password are correct. If both of them are correct, then it redirects to the homepage; otherwise, it produces the message 'Email or Password is incorrect'. First, it queries the database to know if the email exists in the database; then, it checks if the password is correct by using the password_verify() function; after that, it creates PHP sessions, which mark that the user is logged in; and finally, it redirects the user to the homepage by using the header('Location: ./') function.

    If you refresh the login page and login with the correct email and password, you should be redirected to the homepage now. On the homepage, you should see your full name, email, and a logout button.

  9. Now that our login feature is working, let's implement a logout feature. Type the following inside the logout.php:

    <?php
    session_start();
    session_destroy();
    header('Location: ./');
    die();
    

    To log out the user, we have to destroy all the PHP sessions. To do that, we have to use the session_destroy() function. After destroying the session, we have to redirect the user to the homepage.

    The logout button on the homepage should be working now.

  10. Prevents users from accessing the signup and login pages when they are already logged in

    Of course, when the user is logged in, we don't want them to be able to access the signup and login pages. To prevent them, type the following code in check-login.php:

    <?php
    if(!empty($_SESSION['USER_INFORMATION'])) {
        header('Location: ./');
        die();
    }
    

    Now log in to an account, then try to access the signup and login page; it should redirect you to the homepage.

Summary

By now, you should already have a working signup and login system and have hopefully learned a lot from this tutorial. Before we end this tutorial, let's just first summarize what we did and what we should have learned.

The first thing we did in this tutorial was create the file that we would use. In doing that, we are organizing the files in our system. It's a good practice to separate the files for each purpose. For instance, we have the signup and login interfaces separated from our backend codes.

The second thing we did was create our database and database dable. In this part, we should have learned how to execute an SQL code in phpMyAdmin or on the MySQL Command Client. In addition, we should already know how to connect and query from PHP to MySQL using the PDO prepared statement.

Then, we use PHP sessions in several of our files. By now, we should already know how to create, use, and destroy PHP sessions.

After that, in our signup feature, I showed you different ways of validating user input for each type of input. We also hash the password for security. Lastly, in our login feature, I showed you the correct way of verifying the hashed password.

© John Michael Balbarona