https://www.learn2crack.com/2016/04/android-login-registration-php-mysql-server.html


As you guys requested I have finally updated the old Android Login Registration System tutorial with newer code and API. It has all the previous features except Reset Password via Email. I will add that functionality soon and post as separate tutorial.




Some of the changes in Server when compared to the old one,

-> Use PHP PDO for working with MySQL database which is more secure and prevents SQL injection.
-> Code is cleaned and simplified. The total files is 3 instead of 5.
-> Hash password using default PHP BCRYPT algorithm instead of SHA.
-> JSON input instead of form urlencoded data input.

Prerequisites

Install a local web server. Wamp (Windows) or Lamp (Linux). The following video shows you how to setup Wamp in Windows 10,

Creating MySQL Database

Here I have created a database named learn2crack-login-register with table users. After creating the database use the following query to create the users table. Use GUI tool such as phpMyAdmin or MySQL shell to execute the query. In Ubuntu I use Emma a MySQL GUI client.

CREATE TABLE users (
    sno int(11) NOT NULL AUTO_INCREMENT,
    unique_id varchar(23) NOT NULL,
    name varchar(50) NOT NULL,
    email varchar(50) NOT NULL,
    encrypted_password varchar(256) NOT NULL,
    salt varchar(10) NOT NULL,
    created_at datetime DEFAULT NULL,
    PRIMARY KEY (sno)
)

The table has sno, name, email, encrypted_password, salt, created_at fields. The sno is serial number which auto increments and it is the primary key. The encrypted_password and salt field is used to store password hash and random salt string.

Complete Project Files

You can download the complete project as zip or fork from our Github repository.

Files and functions

We have total 3 files instead of 5. The files are DBOperations.php, Functions.php and index.php.

DBOperations.php -> The functions such as connecting with MySQL database and execution of queries are defined in this file.

Functions.php -> The Functions.php file handles all the login, registration and change password functions, also returns JSON response. This Functions.php call the methods defined in DBOperations.php.

index.php -> This is the main file which accepts the input data as JSON and then parses the JSON data and sends the data to Functions.php for further processing.

Now lets discuss what these files does in detail.

DBOperations.php

We define MySQL host address, username for MySQL database, MySQL database name, password as private variables. In the constructor a new MySQL connection is created using PDO and assigned to $conn private variable. The connection is created and assigned by,

$this -> conn = new PDO("mysql:host=".$this -> host.";dbname=".$this -> db, $this -> user, $this -> pass);

The insertData() method is called for registration which accepts name, email and password. We concatenate the password with a random generated String then hash them using PHP’s default BCRYPT hashing algorithm and store in database. If the query is successful the method returns true.

The checkUserExist() method is used to check whether a user is already registered or not using email id. The getHash()method is used to return the generated hash. The verifyHash() method checks whether the password matches the hash using PHP’s password_verify() method. It is used for login.

The checkLogin() method validates the registered user whether the entered email and password combination is correct.

The changePassword() method is used to change old password with a new password.
Note : Here I have defined empty password for MySQL. Replace with your password.

DBOperations.php

<?php

class DBOperations{

    private $host = '127.0.0.1';
    private $user = 'root';
    private $db = 'learn2crack-login-register';
    private $pass = '';
    private $conn;

public function __construct() {

   $this -> conn = new PDO("mysql:host=".$this -> host.";dbname=".$this -> db, $this -> user, $this -> pass);

}

 public function insertData($name,$email,$password){

   $unique_id = uniqid('', true);
    $hash = $this->getHash($password);
    $encrypted_password = $hash["encrypted"];
   $salt = $hash["salt"];

   $sql = 'INSERT INTO users SET unique_id =:unique_id,name =:name,
    email =:email,encrypted_password =:encrypted_password,salt =:salt,created_at = NOW()';

   $query = $this ->conn ->prepare($sql);
   $query->execute(array('unique_id' => $unique_id, ':name' => $name, ':email' => $email,
     ':encrypted_password' => $encrypted_password, ':salt' => $salt));

    if ($query) {

        return true;

    } else {

        return false;

    }
 }

 public function checkLogin($email, $password) {

    $sql = 'SELECT * FROM users WHERE email = :email';
    $query = $this -> conn -> prepare($sql);
    $query -> execute(array(':email' => $email));
    $data = $query -> fetchObject();
    $salt = $data -> salt;
    $db_encrypted_password = $data -> encrypted_password;

    if ($this -> verifyHash($password.$salt,$db_encrypted_password) ) {

        $user["name"] = $data -> name;
        $user["email"] = $data -> email;
        $user["unique_id"] = $data -> unique_id;
        return $user;

    } else {

        return false;
    }
 }

 public function changePassword($email, $password){

    $hash = $this -> getHash($password);
    $encrypted_password = $hash["encrypted"];
    $salt = $hash["salt"];

    $sql = 'UPDATE users SET encrypted_password = :encrypted_password, salt = :salt WHERE email = :email';
    $query = $this -> conn -> prepare($sql);
    $query -> execute(array(':email' => $email, ':encrypted_password' => $encrypted_password, ':salt' => $salt));

    if ($query) {

        return true;

    } else {

        return false;

    }
 }

 public function checkUserExist($email){

    $sql = 'SELECT COUNT(*) from users WHERE email =:email';
    $query = $this -> conn -> prepare($sql);
    $query -> execute(array('email' => $email));

    if($query){

        $row_count = $query -> fetchColumn();

        if ($row_count == 0){

            return false;

        } else {

            return true;

        }
    } else {

        return false;
    }
 }

 public function getHash($password) {

     $salt = sha1(rand());
     $salt = substr($salt, 0, 10);
     $encrypted = password_hash($password.$salt, PASSWORD_DEFAULT);
     $hash = array("salt" => $salt, "encrypted" => $encrypted);

     return $hash;

}

public function verifyHash($password, $hash) {

    return password_verify ($password, $hash);
}
}

Functions.php

DBOperations class instance is created and stored in $db private variable via constructor. This class validates user data such as name, email, password whether it is empty and calls the methods defined in DBOperations class. And finally send JSON response for success or failure. For example consider registerUser() method. Which checks whether user is already registerd or not using checkUserExist() method of DBOperations class. If user exist it sends a error JSON response that “User Already Registered !” or else call the insertData() function of DBOperations class. If data is inserted successfully it send success JSON response that User is Successfully registered.

Similarly loginUser() and changePassword() work. Also two other functions are defined getMsgParamNotEmpty() and getMsgInvalidEmail() which sends back some predefined JSON response.

Functions.php




<?php

require_once 'DBOperations.php';

class Functions{

private $db;

public function __construct() {

      $this -> db = new DBOperations();

}

public function registerUser($name, $email, $password) {

   $db = $this -> db;

   if (!empty($name) && !empty($email) && !empty($password)) {

      if ($db -> checkUserExist($email)) {

         $response["result"] = "failure";
         $response["message"] = "User Already Registered !";
         return json_encode($response);

      } else {

         $result = $db -> insertData($name, $email, $password);

         if ($result) {

              $response["result"] = "success";
            $response["message"] = "User Registered Successfully !";
            return json_encode($response);

         } else {

            $response["result"] = "failure";
            $response["message"] = "Registration Failure";
            return json_encode($response);

         }
      }
   } else {

      return $this -> getMsgParamNotEmpty();

   }
}

public function loginUser($email, $password) {

  $db = $this -> db;

  if (!empty($email) && !empty($password)) {

    if ($db -> checkUserExist($email)) {

       $result =  $db -> checkLogin($email, $password);

       if(!$result) {

        $response["result"] = "failure";
        $response["message"] = "Invaild Login Credentials";
        return json_encode($response);

       } else {

        $response["result"] = "success";
        $response["message"] = "Login Sucessful";
        $response["user"] = $result;
        return json_encode($response);

       }
    } else {

      $response["result"] = "failure";
      $response["message"] = "Invaild Login Credentials";
      return json_encode($response);

    }
  } else {

      return $this -> getMsgParamNotEmpty();
    }
}

public function changePassword($email, $old_password, $new_password) {

  $db = $this -> db;

  if (!empty($email) && !empty($old_password) && !empty($new_password)) {

    if(!$db -> checkLogin($email, $old_password)){

      $response["result"] = "failure";
      $response["message"] = 'Invalid Old Password';
      return json_encode($response);

    } else {

    $result = $db -> changePassword($email, $new_password);

      if($result) {

        $response["result"] = "success";
        $response["message"] = "Password Changed Successfully";
        return json_encode($response);

      } else {

        $response["result"] = "failure";
        $response["message"] = 'Error Updating Password';
        return json_encode($response);

      }
    }
  } else {

      return $this -> getMsgParamNotEmpty();
  }
}

public function isEmailValid($email){

  return filter_var($email, FILTER_VALIDATE_EMAIL);
}

public function getMsgParamNotEmpty(){

  $response["result"] = "failure";
  $response["message"] = "Parameters should not be empty !";
  return json_encode($response);

}

public function getMsgInvalidParam(){

  $response["result"] = "failure";
  $response["message"] = "Invalid Parameters";
  return json_encode($response);

}

public function getMsgInvalidEmail(){

  $response["result"] = "failure";
  $response["message"] = "Invalid Email";
  return json_encode($response);

}
}

index.php

This is the main PHP file. The Functions class is instantiated and assigned to $fun variable as,

$fun = new Functions();

We check whether the Request is POST or GET. For GET request a simple message is returned. For POST the JSON input is decoded and according to the given operation the subsequent method in Functions class is called and response is send back to client. The operations are loginregister and chgPass for Change Password. The JSON objects in Request are operation and user. The user JSON object have some child objects such as name, email, password.

index.php

<?php

require_once 'Functions.php';

$fun = new Functions();

if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
  $data = json_decode(file_get_contents("php://input"));

  if(isset($data -> operation)){

   $operation = $data -> operation;

   if(!empty($operation)){

      if($operation == 'register'){

         if(isset($data -> user ) && !empty($data -> user) && isset($data -> user -> name)
            && isset($data -> user -> email) && isset($data -> user -> password)){

            $user = $data -> user;
            $name = $user -> name;
            $email = $user -> email;
            $password = $user -> password;

          if ($fun -> isEmailValid($email)) {

            echo $fun -> registerUser($name, $email, $password);

          } else {

            echo $fun -> getMsgInvalidEmail();
          }

         } else {

            echo $fun -> getMsgInvalidParam();

         }

      }else if ($operation == 'login') {

        if(isset($data -> user ) && !empty($data -> user) && isset($data -> user -> email) && isset($data -> user -> password)){

          $user = $data -> user;
          $email = $user -> email;
          $password = $user -> password;

          echo $fun -> loginUser($email, $password);

        } else {

          echo $fun -> getMsgInvalidParam();

        }
      } else if ($operation == 'chgPass') {

        if(isset($data -> user ) && !empty($data -> user) && isset($data -> user -> email) && isset($data -> user -> old_password)
          && isset($data -> user -> new_password)){

          $user = $data -> user;
          $email = $user -> email;
          $old_password = $user -> old_password;
          $new_password = $user -> new_password;

          echo $fun -> changePassword($email, $old_password, $new_password);

        } else {

          echo $fun -> getMsgInvalidParam();

        }
      }
   }else{

      echo $fun -> getMsgParamNotEmpty();

   }
  } else {

      echo $fun -> getMsgInvalidParam();

  }
} else if ($_SERVER['REQUEST_METHOD'] == 'GET'){

  echo "Learn2Crack Login API";

}

JSON Request and Response

For example for registration, the input JSON request would be similar to,

{
   "operation":"register",
   "user":{
        "name":"Raj Amal",
        "email":"raj.amalw@learn2crack.com",
        "password":"rajamalw"
   }
}

and if the registration is successful, the response would be,

{
"result":"success",
"message":"User Registered Successfully !"
}

also if registration is not successful, the response would be,

{
"result": "failure",
"message": "User Already Registered !"
}

Similarly for login the request would be similar to,

{
   "operation":"login",
   "user":{
       "email":"raj.amalw@learn2crack.com",
       "password":"rajamalw"
   }
}

and if the credentials are correct, the response would be,

{
    "result": "success",
    "message": "Login Successful",
    "user": {
        "name": "Raj Amal",
        "email": "raj.amalw@learn2crack.com",
        "unique_id": "56fab5891ae0e6.72636328"
  }
}

also for failed login, the response would be,

{
"result": "failure",
"message": "Invaild Login Credentials"
}

Similarly for Change password, the request would be similar to,

{
   "operation":"chgPass",
   "user":{
       "email":"raj.amalw@learn2crack.com",
       "old_password":"rajamal",
       "new_password":"rajamalw"
   }
}

and if the change password operation is sucessful the response would be,

{
"result": "success",
"message": "Password Changed Successfully"
}

also for failed change password operation,

{
"result": "failure",
"message": "Invalid Old Password"
}

Now we have successfully created PHP API for Login Registration. Deploy it in your local Wamp or Lamp to test it using a REST client such as Postman.




Next we can create client Android Application.

Developing Android Application

In the following part you will learn how to develop Android Application and connect with this PHP API

Raj Amal

Raj Amal

Developer at Learn2Crack
Raj Amal is an Android Developer. He Loves to code and explores new technologies. He also authored a book Learning Android Google Maps