Android Login Registration System with PHP and MySQL (Updated) – Server #1
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.
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.
Install a local web server. Wamp (Windows) or Lamp (Linux). The following video shows you how to setup Wamp in Windows 10,
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.
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,
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.
$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.
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.
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);
}
}