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.
You can download the complete project as zip or fork from our Github repository.
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.
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.
<?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);
}
}
A 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.
<?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);
}
}
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 login, register 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.
<?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