Android adding SMS Verification Like WhatsApp – Part 1

My previous tutorial explains how to implement the user login / registration by collecting user name, email and password. But what if you want to sign up an user using their mobile number like WhatsApp, Viber by verifying their mobile number in order to get genuine users.

Before going further make sure that you have basic knowledge about android client-sever communication. If you are new to this, don’t worry, these articles (MySQL Spinner & PHP, MySQL – Android) gives you a good start.

As this article seems lengthy, I have divided it into two parts. In this part we’ll learn the server side part i.e building the PHP, MySQL project by integrating the SMS gateway. In the 2nd part we cover the implementation of android app.

android-sms-verification-like-whatsapp

1. How It Works

Below is the simple architecture diagram that explains the process of complete registration which involves the PHP, MySQL server and a SMS gateway.

android-sms-verification-php-mysql

1. First user mobile number will be sent to our server where new user row will be created.

2. Our server requests the SMS gateway for an sms to the mobile number with a verification code.

3. SMS gateway sends an SMS to the user device with the verification code.

4. The verification code will be sent back our server again for verification. Our server verifies it and activates the user.

2. Choosing the SMS Gateway

SMS gateways are helpful in sending an SMS to any mobile number that comes under any mobile network. Basically gateways have a contract with all the mobile networks to send the SMS to a particular mobile number. In INDIA we have lot of SMS providers, but choosing the best SMS service provider is difficult. I found Solutions Infini, SMS Gupshup, Value First and Msg91 are quite popular. But the most important thing keep in mind while choosing the provider is make sure that they do support REST API as our server needs to trigger an SMS whenever a request comes from the android app.

Unfortunately there are no free SMS gateways to test your android app. You have to contact any of the service providers seeking for a demo account or buy the SMS credits.

3. Signing up with MSG91 (API Key)

To demonstrate the tutorial, I have selected Msg91 gateway for their simplicity. Follow the below steps to get register and obtain your REST API Key. Please be aware that this gateway is for INDIAN users only. If you are not from INDIA, choose the gateway which is available in your country.

1. Signup with Msg91.

2. Buy the SMS credits by selecting the appropriate details. In the form select SMS Type as
TRANSACTIONAL ROUTE and give no.of SMS as 2500 which is minimum credits to buy. The cost would be around ₹600.

3. Proceed with the payment. Once the payment was done, you can see the SMS credits credited into your account.

4. To obtain your API key, goto the API doc and click on KEY on the top right corner. You will be shown your API Key in a popup dialog. Copy this API Key, we’re gonna need it in our PHP project.

Check the below video demonstrating buying the SMS credits on Msg91.

4. Building the PHP, MySQL REST API

Now we have the API Key needed to send the SMS. Let’s start building the PHP project needed for the android app. We are going to build a simple REST API to manage the users who signs up using the android app. At the end of this project, we should be able to build two end points needed for the user registration. One is to register user which sends an SMS with a verification code. Second endpoint is to verify the code and completes the user registration.

4.1 Installing WAMP software

Download & Install WAMP server from www.wampserver.com/en/. Once WAMP is installed, launch the program from Start ⇒ All Programs ⇒ WampServer ⇒ StartWampServer. If you are on Mac, MAMP will be useful.

You can test your server by opening the address http://localhost/ in your browser.
Also you can check phpmyadmin by opening http://localhost/phpmyadmin

4.2 Creating MySQL Database

For this project we need two tables. One is users table to store the user information and second one is sms_codes to store the user’s sms verification codes.

Below are the columns needed in each table.

android sms verification mysql database

Open http://localhost/phpmyadmin and execute below queries to create required database and tables.

Create a database named android_sms.

CREATE DATABASE android_sms;

USE android_sms;

Create required tables and relationship by executing below sql queries.

CREATE TABLE `sms_codes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `code` varchar(6) NOT NULL,
  `status` int(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;


CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `email` varchar(250) NOT NULL,
  `mobile` varchar(10) NOT NULL,
  `apikey` varchar(32) NOT NULL,
  `status` int(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=64 ;


ALTER TABLE `sms_codes`
  ADD CONSTRAINT `sms_codes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

4.3 Creating PHP Project

Once you are done with database setup, let’s move to php project development. You can use any IDE like Netbeans to develop this project or just the notepad++ is enough.

1. Goto the WAMP project directory i.e C:/wamp/www and create a folder named android_sms. This will be the root directory of our PHP project.

2. Inside android_sms, create a folder named include. In this folder we keep all the configuration like database credentials, Msg91 API Key etc.,

3. Create a file under include folder named Config.php and add below code. Replace the MySQL credentials and Msg91 API Key in the below code with yours.

<?php
/**
 * Database configuration
 */
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'root');
define('DB_HOST', 'localhost');
define('DB_NAME', 'android_sms');


/**
 * MSG91 configuration
 */
define('MSG91_AUTH_KEY', "88276AGwzewOEdFs559d2888");
// sender id should 6 character long
define('MSG91_SENDER_ID', 'ANHIVE');

define('USER_CREATED_SUCCESSFULLY', 0);
define('USER_CREATE_FAILED', 1);
define('USER_ALREADY_EXISTED', 2);
?>

4. Under include folder, create another php file named DbConnect.php This file handles the database connection.

<?php

/**
 * Handling database connection
 *
 * @author Ravi Tamada
 * @link URL Tutorial link
 */
class DbConnect {

    private $conn;

    function __construct() {        
    }

    /**
     * Establishing database connection
     * @return database connection handler
     */
    function connect() {
        include_once dirname(__FILE__) . '/Config.php';

        // Connecting to mysql database
        $this->conn = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);

        // Check for database connection error
        if (mysqli_connect_errno()) {
            echo "Failed to connect to MySQL: " . mysqli_connect_error();
            exit;
        }

        // returing connection resource
        return $this->conn;
    }

}

?>

5. Create another php file named DbHandler.php under include folder. This file contains the major functions to perform the read, write operations onto database.

<?php

/**
 * Class to handle all db operations
 * This class will have CRUD methods for database tables
 *
 * @author Ravi Tamada
 * @link URL Tutorial link
 */
class DbHandler {

    private $conn;

    function __construct() {
        require_once dirname(__FILE__) . '/DbConnect.php';
        // opening db connection
        $db = new DbConnect();
        $this->conn = $db->connect();
    }

    /* ------------- `users` table method ------------------ */

    /**
     * Creating new user
     * @param String $name User full name
     * @param String $email User login email id
     * @param String $mobile User mobile number
     * @param String $otp user verificaiton code
     */
    public function createUser($name, $email, $mobile, $otp) {
        $response = array();

        // First check if user already existed in db
        if (!$this->isUserExists($mobile)) {

            // Generating API key
            $api_key = $this->generateApiKey();

            // insert query
            $stmt = $this->conn->prepare("INSERT INTO users(name, email, mobile, apikey, status) values(?, ?, ?, ?, 0)");
            $stmt->bind_param("ssss", $name, $email, $mobile, $api_key);

            $result = $stmt->execute();

            $new_user_id = $stmt->insert_id;

            $stmt->close();

            // Check for successful insertion
            if ($result) {

                $otp_result = $this->createOtp($new_user_id, $otp);

                // User successfully inserted
                return USER_CREATED_SUCCESSFULLY;
            } else {
                // Failed to create user
                return USER_CREATE_FAILED;
            }
        } else {
            // User with same email already existed in the db
            return USER_ALREADY_EXISTED;
        }

        return $response;
    }

    public function createOtp($user_id, $otp) {

        // delete the old otp if exists
        $stmt = $this->conn->prepare("DELETE FROM sms_codes where user_id = ?");
        $stmt->bind_param("i", $user_id);
        $stmt->execute();


        $stmt = $this->conn->prepare("INSERT INTO sms_codes(user_id, code, status) values(?, ?, 0)");
        $stmt->bind_param("is", $user_id, $otp);

        $result = $stmt->execute();

        $stmt->close();

        return $result;
    }
    
    /**
     * Checking for duplicate user by mobile number
     * @param String $email email to check in db
     * @return boolean
     */
    private function isUserExists($mobile) {
        $stmt = $this->conn->prepare("SELECT id from users WHERE mobile = ? and status = 1");
        $stmt->bind_param("s", $mobile);
        $stmt->execute();
        $stmt->store_result();
        $num_rows = $stmt->num_rows;
        $stmt->close();
        return $num_rows > 0;
    }

    public function activateUser($otp) {
        $stmt = $this->conn->prepare("SELECT u.id, u.name, u.email, u.mobile, u.apikey, u.status, u.created_at FROM users u, sms_codes WHERE sms_codes.code = ? AND sms_codes.user_id = u.id");
        $stmt->bind_param("s", $otp);

        if ($stmt->execute()) {
            // $user = $stmt->get_result()->fetch_assoc();
            $stmt->bind_result($id, $name, $email, $mobile, $apikey, $status, $created_at);
            
            $stmt->store_result();

            if ($stmt->num_rows > 0) {
                
                $stmt->fetch();
                
                // activate the user
                $this->activateUserStatus($id);
                
                $user = array();
                $user["name"] = $name;
                $user["email"] = $email;
                $user["mobile"] = $mobile;
                $user["apikey"] = $apikey;
                $user["status"] = $status;
                $user["created_at"] = $created_at;
                
                $stmt->close();
                
                return $user;
            } else {
                return NULL;
            }
        } else {
            return NULL;
        }

        return $result;
    }
    
    public function activateUserStatus($user_id){
        $stmt = $this->conn->prepare("UPDATE users set status = 1 where id = ?");
        $stmt->bind_param("i", $user_id);
        
        $stmt->execute();
        
        $stmt = $this->conn->prepare("UPDATE sms_codes set status = 1 where user_id = ?");
        $stmt->bind_param("i", $user_id);
        
        $stmt->execute();
    }

    /**
     * Generating random Unique MD5 String for user Api key
     */
    private function generateApiKey() {
        return md5(uniqid(rand(), true));
    }
}
?>

6. Now we have all the core logic ready. Let’s create an endpoint to register the user. In your project’s root directory, create a file named request_sms.php.

In below code

> First we receive the name, email and mobile number those were sent from the android device as a POST parameters.

> We create an entry in users table by calling createUser() function. Initially the user status will be 0 which indicate the user is inactive. This status will be made to 1 when the user verifies the OTP.

> Once the user row is created, we request for an SMS to the mobile number by calling sendSms() method.

> sendSms() method will make a call to Msg91 REST API to send SMS with a 6 digits OTP to the users mobile number.

Below is the sample SMS message the user will receive to their mobile. The OTP should be prefixed by : and space in the message.

Hello! Welcome to AndroidHive. Your OPT is : 228767
<?php

include './include/DbHandler.php';
$db = new DbHandler();


$response = array();

if (isset($_POST['mobile']) && $_POST['mobile'] != '') {

    $name = $_POST['name'];
    $email = $_POST['email'];
    $mobile = $_POST['mobile'];

    $otp = rand(100000, 999999);

    $res = $db->createUser($name, $email, $mobile, $otp);

    if ($res == USER_CREATED_SUCCESSFULLY) {
        
        // send sms
        sendSms($mobile, $otp);
        
        $response["error"] = false;
        $response["message"] = "SMS request is initiated! You will be receiving it shortly.";
    } else if ($res == USER_CREATE_FAILED) {
        $response["error"] = true;
        $response["message"] = "Sorry! Error occurred in registration.";
    } else if ($res == USER_ALREADY_EXISTED) {
        $response["error"] = true;
        $response["message"] = "Mobile number already existed!";
    }
} else {
    $response["error"] = true;
    $response["message"] = "Sorry! mobile number is not valid or missing.";
}

echo json_encode($response);

function sendSms($mobile, $otp) {
    
    $otp_prefix = ':';

    //Your message to send, Add URL encoding here.
    $message = urlencode("Hello! Welcome to AndroidHive. Your OPT is '$otp_prefix $otp'");

    $response_type = 'json';

    //Define route 
    $route = "4";
    
    //Prepare you post parameters
    $postData = array(
        'authkey' => MSG91_AUTH_KEY,
        'mobiles' => $mobile,
        'message' => $message,
        'sender' => MSG91_SENDER_ID,
        'route' => $route,
        'response' => $response_type
    );

//API URL
    $url = "https://control.msg91.com/sendhttp.php";

// init the resource
    $ch = curl_init();
    curl_setopt_array($ch, array(
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $postData
            //,CURLOPT_FOLLOWLOCATION => true
    ));


    //Ignore SSL certificate verification
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);


    //get response
    $output = curl_exec($ch);

    //Print error if any
    if (curl_errno($ch)) {
        echo 'error:' . curl_error($ch);
    }

    curl_close($ch);
}
?>

7. Now we need to create another endpoint to verify the OTP. Create a php file named verify_otp.php with below content.

In the below code

> The OTP will be received from the android device as a POST param.

> The user who matches with OTP will fetched from the users table.

> Then the user status will be set to 1 in both users and sms_codes table which makes the user active.

> The above two steps are implemented in activateUser() function.

<?php

include './include/DbHandler.php';
$db = new DbHandler();


$response = array();
$response["error"] = false;

if (isset($_POST['otp']) && $_POST['otp'] != '') {
    $otp = $_POST['otp'];


    $user = $db->activateUser($otp);

    if ($user != NULL) {

        $response["message"] = "User created successfully!";
        $response["profile"] = $user;
    } else {
        $response["message"] = "Sorry! Failed to create your account.";
    }
    
    
} else {
    $response["message"] = "Sorry! OTP is missing.";
}


echo json_encode($response);
?>

5. Testing the REST API

To test our API, install Postman chrome extension which allows you to test the endpoints by passing the parameters required.

Request SMS

URLMethodParametersDescription
http://localhost/android_sms/request_sms.phpPOSTname, email, mobileRequest SMS

The below json should be produced when SMS sent successfully.

{
    "error": false,
    "message": "SMS request is initiated! You will be receiving it shortly."
}

Verifying user OTP

URLMethodParametersDescription
http://localhost/android_sms/verify_otp.phpPOSTotpverifying user verification code

When the OTP is verified successfully, the complete user profile information should be produced in the json.

{
    "error": false,
    "message": "User created successfully!",
    "profile": {
        "name": "Ravi Tamada",
        "email": "ravi@androidhive.info",
        "mobile": "0000000000",
        "apikey": "088d196bacbe6bf08657720c9d562390",
        "status": 0,
        "created_at": "2015-07-30 22:18:59"
    }
}

Watch the below video know how to use Postman to test the endpoints.

This completes the server side part. In the 2nd part we are going to learn how to create the android app by integrating the API we have just built.

Ravi is hardcore Android programmer and Android programming has been his passion since he compiled his first hello-world program. Solving real problems of Android developers through tutorials has always been interesting part for him.