Login and Registration using PHP and RESTful API

Author - Neelima Mohanty
29/02/2022 | 10:30 PM


Hello everyone ! In this tutorial, you will learn how to create a Login and Registration RESTful API using PHP and MySQL Database.



Prerequisites

• Knowledge about basic web framework(HTML,CSS,Javascript).
• Familiarity with Python programming language.
• XAMPP
• PHP
• MySQL



Tutorial Begins

Follow the steps written below:

Step 1 : MySQL Database Setup

First, we will set up the MySQL Database for this application.

Database Name – php_auth_api
Table Name – users

Go inside your MySQL Database and create a new Database called php_auth_api. After that, use the following SQL code to create the users table and the structure of this table –

CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Step 2 : Creating files & folders

First, Open your Xampp htdocs dir or your server www dir, and here create a new folder called php-auth-api. This is our application folder. After that, you need to install JWT inside this folder, as we will be using it for authorization.

Now we need to create the folders and files as given in the following image of the php-auth-api folder structure.

Inside the application folder, you need to create a new folder called classes, and inside the classes folder, we will create two files or classes –

Database.php – For making the database connection.
JwtHandler.php – For handling the JWT actions like encoding and decoding token.

Database.php
class Database{
// CHANGE THE DB INFO ACCORDING TO YOUR DATABASE
private $db_host = 'localhost';
private $db_name = 'php_auth_api';
private $db_username = 'root';
private $db_password = '';
public function dbConnection(){
    try{
        $conn = new PDO('mysql:host='.$this->db_host.';dbname='.$this->db_name,$this->db_username,$this->db_password);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $conn;
    }
    catch(PDOException $e){
        echo "Connection error ".$e->getMessage();
        exit;
    }
}
}

Also add this

JwtHandler.php
require './vendor/autoload.php';
use Firebase\JWT\JWT;
class JwtHandler
{
    protected $jwt_secrect;
    protected $token;
    protected $issuedAt;
    protected $expire;
    protected $jwt;
    public function __construct()
    {
        // set your default time-zone
        date_default_timezone_set('Asia/Kolkata');
        $this->issuedAt = time();
        // Token Validity (3600 second = 1hr)
        $this->expire = $this->issuedAt + 3600;
        // Set your secret or signature
        $this->jwt_secrect = "this_is_my_secrect";
    }
    public function jwtEncodeData($iss, $data)
    {
        $this->token = array(
        //Adding the identifier to the token (who issue the token)
        "iss" => $iss,
        "aud" => $iss,
        // Adding the current timestamp to the token, for identifying that when the token was issued.
        "iat" => $this->issuedAt,
        // Token expiration
        "exp" => $this->expire,
        // Payload
        "data" => $data
    );
    $this->jwt = JWT::encode($this->token, $this->jwt_secrect, 'HS256');
    return $this->jwt;
    }
    public function jwtDecodeData($jwt_token)
    {
    try {
    $decode = JWT::decode($jwt_token, $this->jwt_secrect, array('HS256'));
    return [
    "data" => $decode->data
    ];
    } catch (Exception $e) {
    return [
    "message" => $e->getMessage()
     ];
    }
  }
}

Create AuthMiddleware.php This file is for checking whether the token is valid or not.

AuthMiddleware.php
require __DIR__ . '/classes/JwtHandler.php';
class Auth extends JwtHandler
{
    protected $db;
    protected $headers;
    protected $token;
    public function __construct($db, $headers)
    {
        parent::__construct();
        $this->db = $db;
        $this->headers = $headers;
    }
    public function isValid()
    {
        if (array_key_exists('Authorization', $this->headers) && preg_match('/Bearer\s(\S+)/', $this->headers['Authorization'], $matches)) {
        $data = $this->jwtDecodeData($matches[1]);
        if (
            isset($data['data']->user_id) &&
            $user = $this->fetchUser($data['data']->user_id)
            ) :
            return [
                "success" => 1,
                "user" => $user
              ];
        else :
            return [
              "success" => 0,
              "message" => $data['message'],
        ];
    endif;
    } else {
        return [
            "success" => 0,
            "message" => "Token not found in request"
        ];
      }
    }
    protected function fetchUser($user_id)
{
    try {
        $fetch_user_by_id = "SELECT `name`,`email` FROM `users` WHERE `id`=:id";
        $query_stmt = $this->db->prepare($fetch_user_by_id);
        $query_stmt->bindValue(':id', $user_id, PDO::PARAM_INT);
        $query_stmt->execute();
        if ($query_stmt->rowCount()) :
            return $query_stmt->fetch(PDO::FETCH_ASSOC);
        else :
            return false;
        endif;
        } catch (PDOException $e) {
        return null;
    }
    }
}

Rest of the PHP files
register.php – For user registration.
login.php – For user login.
getUser.php – After login, this page is accessible with a valid token.

register.php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require __DIR__ . '/classes/Database.php';
$db_connection = new Database();
$conn = $db_connection->dbConnection();
function msg($success, $status, $message, $extra = [])
{
    return array_merge([
        'success' => $success,
        'status' => $status,
        'message' => $message
    ], $extra);
}
// DATA FORM REQUEST
$data = json_decode(file_get_contents("php://input"));
$returnData = [];
if ($_SERVER["REQUEST_METHOD"] != "POST") :
    $returnData = msg(0, 404, 'Page Not Found!');
elseif (     !isset($data->name)
    || !isset($data->email)
    || !isset($data->password)
    || empty(trim($data->name))
    || empty(trim($data->email))
    || empty(trim($data->password))
) :
    $fields = ['fields' => ['name', 'email', 'password']];
    $returnData = msg(0, 422, 'Please Fill in all Required Fields!', $fields);
    // IF THERE ARE NO EMPTY FIELDS THEN-
else :
    $name = trim($data->name);
    $email = trim($data->email);
    $password = trim($data->password);
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) :
        $returnData = msg(0, 422, 'Invalid Email Address!');
    elseif (strlen($password) < 8) :
        $returnData = msg(0, 422, 'Your password must be at least 8 characters long!');
    elseif (strlen($name) < 3) :
        $returnData = msg(0, 422, 'Your name must be at least 3 characters long!');
    else :
      try {
          $check_email = "SELECT `email` FROM `users` WHERE `email`=:email";
          $check_email_stmt = $conn->prepare($check_email);
          $check_email_stmt->bindValue(':email', $email, PDO::PARAM_STR);
          $check_email_stmt->execute();
          if ($check_email_stmt->rowCount()) :
            $returnData = msg(0, 422, 'This E-mail already in use!');
          else :
            $insert_query = "INSERT INTO `users`(`name`,`email`,`password`) VALUES(:name,:email,:password)";
            $insert_stmt = $conn->prepare($insert_query);
            // DATA BINDING
            $insert_stmt->bindValue(':name', htmlspecialchars(strip_tags($name)), PDO::PARAM_STR);
            $insert_stmt->bindValue(':email', $email, PDO::PARAM_STR);
            $insert_stmt->bindValue(':password', password_hash($password, PASSWORD_DEFAULT), PDO::PARAM_STR);
            $insert_stmt->execute();
            $returnData = msg(1, 201, 'You have successfully registered.');
            endif;
            } catch (PDOException $e) {
              $returnData = msg(0, 500, $e->getMessage());
              }
        endif;
    endif;
echo json_encode($returnData);
login.php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: POST");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require __DIR__.'/classes/Database.php';
require __DIR__.'/classes/JwtHandler.php';
function msg($success,$status,$message,$extra = []){
    return array_merge([
        'success' => $success,
        'status' => $status,
        'message' => $message
    ],$extra);
}
$db_connection = new Database();
$conn = $db_connection->dbConnection();
$data = json_decode(file_get_contents("php://input"));
$returnData = [];
// IF REQUEST METHOD IS NOT EQUAL TO POST
if($_SERVER["REQUEST_METHOD"] != "POST"):
$returnData = msg(0,404,'Page Not Found!');
// CHECKING EMPTY FIELDS
elseif(!isset($data->email)
    || !isset($data->password)
    || empty(trim($data->email))
    || empty(trim($data->password))
    ):
    $fields = ['fields' => ['email','password']];
    $returnData = msg(0,422,'Please Fill in all Required Fields!',$fields);
// IF THERE ARE NO EMPTY FIELDS THEN-
else:
    $email = trim($data->email);
    $password = trim($data->password);
    // CHECKING THE EMAIL FORMAT (IF INVALID FORMAT)
    if(!filter_var($email, FILTER_VALIDATE_EMAIL)):
        $returnData = msg(0,422,'Invalid Email Address!');
         // IF PASSWORD IS LESS THAN 8 THE SHOW THE ERROR
        elseif(strlen($password) < 8):
          $returnData = msg(0,422,'Your password must be at least 8 characters long!');
// THE USER IS ABLE TO PERFORM THE LOGIN ACTION
else:
    try{
        $fetch_user_by_email = "SELECT * FROM `users` WHERE `email`=:email";
        $query_stmt = $conn->prepare($fetch_user_by_email);
        $query_stmt->bindValue(':email', $email,PDO::PARAM_STR);
        $query_stmt->execute();
// IF THE USER IS FOUNDED BY EMAIL
        if($query_stmt->rowCount()):
          $row = $query_stmt->fetch(PDO::FETCH_ASSOC);
          $check_password = password_verify($password, $row['password']);
          // VERIFYING THE PASSWORD (IS CORRECT OR NOT?)
// IF PASSWORD IS CORRECT THEN SEND THE LOGIN TOKEN
        if($check_password):
          $jwt = new JwtHandler();
          $token = $jwt->jwtEncodeData(
          'http://localhost/php_auth_api/',
          array("user_id"=> $row['id'])
      );
      $returnData = [
        'success' => 1,
        'message' => 'You have successfully logged in.',
        'token' => $token
       ];
// IF INVALID PASSWORD
        else:
          $returnData = msg(0,422,'Invalid Password!');
        endif;
// IF THE USER IS NOT FOUNDED BY EMAIL THEN SHOW THE FOLLOWING ERROR
        else:
          $returnData = msg(0,422,'Invalid Email Address!');
         endif;
    }
        catch(PDOException $e){
          $returnData = msg(0,500,$e->getMessage());
    }
    endif;
endif;
echo json_encode($returnData);
getUser.php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: GET");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require __DIR__.'/classes/Database.php';
require __DIR__.'/AuthMiddleware.php';
$allHeaders = getallheaders();
$db_connection = new Database();
$conn = $db_connection->dbConnection();
$auth = new Auth($conn, $allHeaders);
echo json_encode($auth->isValid());

Step 3 : Testing of the PHP login and registration API

register.php
POST - http://localhost/php-auth-api/register.php
Payload (JSON)
{
    "name":"username",
    "email":"useremail@mail.com",
    "password":"user password" }
login.php
POST - http://localhost/php-auth-api/login.php
Payload (JSON)
{
    "email":"useremail@mail.com",
    "password":"user password"
}
getUser.php
GET - http://localhost/php-auth-api/getUser.php
Payload (Header)
Authorization - Bearer Token


Congratulations


People who read this also read

article

Application of smtplib module

Author: Neelima Mohanty
20/01/2022 | 10:30 PM