Android Building Realtime Chat App using GCM, PHP & MySQL – Part 1

Google Cloud Messaging allows you send lightweight messages from the backend server to all the devices whenever there is new data available. This saves lot of user’s battery by avoiding poll request to server for new data. Using GCM you can build powerful multi platform (iOS, Android & Web) apps like real time chat, news feed, cloud storage and lot more. On top of everything, GCM is completely free and there are no limitations.

As parse.com announced their shutdown recently, GCM is the only best option even though it won’t comes with an admin interface. But don’t worry, we’ll build a simple admin panel in this article.

android realtime chat app using gcm php mysql

As this article is pretty lengthy, I have divided it into 3 parts. Each part covers a unique part in building the final realtime chat app.

Part 1: Covers building the REST API for chat app including the GCM server app.

Part 2: Explains integrating GCM into your android app including a test message.

Part 3: Building Simple Realtime Chat App.

1. Google Cloud Messaging

Typically GCM implementation involves three components. Google cloud messaging server, the app server and the client app. We should take care of writing the app server and the client app. In order to make calls from the app server to GCM server, you can follow HTTP or XMPP protocol. HTTP supports downstream (gcm to client) messages only. XMPP supports both downstream and upstream (device to gcm, then from gcm to server) messages.

Below is the pictorial representation of the overall architecture.

android-google-cloud-messaging-architecture

1. First the app connects to GCM server and register itself.

2. Upon successful registration, GCM issues gcm registration token to device. This registration token uniquely identifies each device.

3. The device sends the registration token to our server to store it in MySQL.

4. Whenever app server wants to send push notification, it sends a request to GCM server sending the push message along with the registration token.

5. GCM server identifies the device using the registration token and initiates the push message.

6. The device receives the push messages and further action takes place.

2. Obtaining Google API Key

Google API key is necessary to interact with GCM server. GCM uses this key to identify your server app. Follow the below steps to obtain your API key. Note that the developer console interface is changing more frequently. So, the below steps may vary in future.

1. Goto Google developers console and create a new app. If you have already created one, select the app.

2. Give a name to your new project. Once the project is created, goto project’s dashboard and click on Use Google APIs

3. Under Mobile APIs, click on Cloud Messaging for Android and enable the API by clicking on top enable API button.

4. Once enabled, click on Credentials on the left. You will be asked to create new credentials by showing multiple options. Choose API Key and then Server Key.

5. After choosing Server Key, your API key will be displayed on the dashboard. Note down the API key as we need to use it in our PHP project.

3. Building Simple Realtime Chat App

In this article, we are going to learn how to create a simple realtime chat app by using Android, GCM, PHP, MySQL, HTML & CSS. We use HTML & CSS to build the admin panel for the server app.

Below are the screens of the android app.

android-simple-chat-app-using-gcm-php-mysql

And the server app comes with the option of choosing the user(s) / topic and send the push notification.

android-php-mysql-gcm-chat-app-admin-panel

This part of the article involves building the server app including designing the MySQL database, REST API for mobile app and an admin panel to send push notifications. I am using Netbeans IDE to develop the PHP code and WAMP / MAMP server to create the php, mysql environment.

Now let’s start designing the database first.

4. Designing MySQL Database

For this app we need only three tables. users, chat rooms and messages.

users – This table holds the user information like name, email and other profile information along with gcm registration id.

chat_rooms – Contains the chat room information.

messages – Contains the messages sent in the chat rooms.

android-simple-chat-app-mysql-database

Open phpmyadmin and execute the below sql query to create the required database and tables.

CREATE DATABASE gcm_chat;

CREATE TABLE `chat_rooms` (
  `chat_room_id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

CREATE TABLE `messages` (
  `message_id` int(11) NOT NULL,
  `chat_room_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `message` text NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `users` (
  `user_id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `gcm_registration_id` text NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `chat_rooms`
  ADD PRIMARY KEY (`chat_room_id`);

ALTER TABLE `messages`
  ADD PRIMARY KEY (`message_id`),
  ADD KEY `chat_room_id` (`chat_room_id`),
  ADD KEY `user_id` (`user_id`),
  ADD KEY `chat_room_id_2` (`chat_room_id`);

ALTER TABLE `users`
  ADD PRIMARY KEY (`user_id`),
  ADD UNIQUE KEY `email` (`email`);

ALTER TABLE `messages`
  ADD CONSTRAINT `messages_ibfk_3` FOREIGN KEY (`chat_room_id`) REFERENCES `chat_rooms` (`chat_room_id`),
  ADD CONSTRAINT `messages_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;

5. Creating PHP REST API

I am using Slim framework to create the REST endpoints. If you are not aware of PHP Slim, refer my previous tutorial REST API for Android app using PHP, Slim and MySQL to understand how easily you can create the REST API endpoints for your android app.

Below is the project structure of the PHP app. You have to make sure that you are following same structure while following the further steps.

gcm-simple-chat-app-php-mysql-project

include – Contains the database classes to perform CRUD operations on the database.

libs – Contains the libraries needed for the app (slim, gcm)

v1 – Root directory of the REST API

index.php, demo.php, styles.css – Required to create the admin interface.

1. Goto your WAMP/MAMP installation location and open the web directory. On windows, it will be c:/wamp/www directory. On Mac, the path will be /Applications/MAMP/htdocs.

2. Inside the web directory (www or htdocs), create a directory named gcm_chat. This will be the root directory of our project.

3. Inside gcm_chat folder, create the remaining directories as shown in the above image. Create folders named include, libs and v1. Inside libs, create another folder named gcm.

4. Download Slim framework and paste it inside libs folder.

5. Create a file named config.php in include. This file contains the app configuration like database credentials, google API Key and other information.

Replace GOOGLE_API_KEY with your API Key which you obtained in 2nd section. Also keep the correct database credentials.

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

define("GOOGLE_API_KEY", "AIzaSyDKk_Ew7Vi4FZnMzu6GCY5PLb4xZG8muvX");

// push notification flags
define('PUSH_FLAG_CHATROOM', 1);
define('PUSH_FLAG_USER', 2);

?>

6. Create a file named db_connect.php inside include folder. This class takes care of database connection.

<?php

/**
 * Handling database connection
 *
 */
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();
        }

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

7. Create another file named db_handler.php inside include folder. This file contains all the necessary functions to interact with database tables.

<?php

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

    private $conn;

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

    // creating new user if not existed
    public function createUser($name, $email) {
        $response = array();

        // First check if user already existed in db
        if (!$this->isUserExists($email)) {
            // insert query
            $stmt = $this->conn->prepare("INSERT INTO users(name, email) values(?, ?)");
            $stmt->bind_param("ss", $name, $email);

            $result = $stmt->execute();

            $stmt->close();

            // Check for successful insertion
            if ($result) {
                // User successfully inserted
                $response["error"] = false;
                $response["user"] = $this->getUserByEmail($email);
            } else {
                // Failed to create user
                $response["error"] = true;
                $response["message"] = "Oops! An error occurred while registereing";
            }
        } else {
            // User with same email already existed in the db
            $response["error"] = false;
            $response["user"] = $this->getUserByEmail($email);
        }

        return $response;
    }

    // updating user GCM registration ID
    public function updateGcmID($user_id, $gcm_registration_id) {
        $response = array();
        $stmt = $this->conn->prepare("UPDATE users SET gcm_registration_id = ? WHERE user_id = ?");
        $stmt->bind_param("si", $gcm_registration_id, $user_id);

        if ($stmt->execute()) {
            // User successfully updated
            $response["error"] = false;
            $response["message"] = 'GCM registration ID updated successfully';
        } else {
            // Failed to update user
            $response["error"] = true;
            $response["message"] = "Failed to update GCM registration ID";
            $stmt->error;
        }
        $stmt->close();

        return $response;
    }

    // fetching single user by id
    public function getUser($user_id) {
        $stmt = $this->conn->prepare("SELECT user_id, name, email, gcm_registration_id, created_at FROM users WHERE user_id = ?");
        $stmt->bind_param("s", $user_id);
        if ($stmt->execute()) {
            // $user = $stmt->get_result()->fetch_assoc();
            $stmt->bind_result($user_id, $name, $email, $gcm_registration_id, $created_at);
            $stmt->fetch();
            $user = array();
            $user["user_id"] = $user_id;
            $user["name"] = $name;
            $user["email"] = $email;
            $user["gcm_registration_id"] = $gcm_registration_id;
            $user["created_at"] = $created_at;
            $stmt->close();
            return $user;
        } else {
            return NULL;
        }
    }

    // fetching multiple users by ids
    public function getUsers($user_ids) {

        $users = array();
        if (sizeof($user_ids) > 0) {
            $query = "SELECT user_id, name, email, gcm_registration_id, created_at FROM users WHERE user_id IN (";

            foreach ($user_ids as $user_id) {
                $query .= $user_id . ',';
            }

            $query = substr($query, 0, strlen($query) - 1);
            $query .= ')';

            $stmt = $this->conn->prepare($query);
            $stmt->execute();
            $result = $stmt->get_result();

            while ($user = $result->fetch_assoc()) {
                $tmp = array();
                $tmp["user_id"] = $user['user_id'];
                $tmp["name"] = $user['name'];
                $tmp["email"] = $user['email'];
                $tmp["gcm_registration_id"] = $user['gcm_registration_id'];
                $tmp["created_at"] = $user['created_at'];
                array_push($users, $tmp);
            }
        }

        return $users;
    }

    // messaging in a chat room / to persional message
    public function addMessage($user_id, $chat_room_id, $message) {
        $response = array();

        $stmt = $this->conn->prepare("INSERT INTO messages (chat_room_id, user_id, message) values(?, ?, ?)");
        $stmt->bind_param("iis", $chat_room_id, $user_id, $message);

        $result = $stmt->execute();

        if ($result) {
            $response['error'] = false;

            // get the message
            $message_id = $this->conn->insert_id;
            $stmt = $this->conn->prepare("SELECT message_id, user_id, chat_room_id, message, created_at FROM messages WHERE message_id = ?");
            $stmt->bind_param("i", $message_id);
            if ($stmt->execute()) {
                $stmt->bind_result($message_id, $user_id, $chat_room_id, $message, $created_at);
                $stmt->fetch();
                $tmp = array();
                $tmp['message_id'] = $message_id;
                $tmp['chat_room_id'] = $chat_room_id;
                $tmp['message'] = $message;
                $tmp['created_at'] = $created_at;
                $response['message'] = $tmp;
            }
        } else {
            $response['error'] = true;
            $response['message'] = 'Failed send message';
        }

        return $response;
    }

    // fetching all chat rooms
    public function getAllChatrooms() {
        $stmt = $this->conn->prepare("SELECT * FROM chat_rooms");
        $stmt->execute();
        $tasks = $stmt->get_result();
        $stmt->close();
        return $tasks;
    }

    // fetching single chat room by id
    function getChatRoom($chat_room_id) {
        $stmt = $this->conn->prepare("SELECT cr.chat_room_id, cr.name, cr.created_at as chat_room_created_at, u.name as username, c.* FROM chat_rooms cr LEFT JOIN messages c ON c.chat_room_id = cr.chat_room_id LEFT JOIN users u ON u.user_id = c.user_id WHERE cr.chat_room_id = ?");
        $stmt->bind_param("i", $chat_room_id);
        $stmt->execute();
        $tasks = $stmt->get_result();
        $stmt->close();
        return $tasks;
    }

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

    /**
     * Fetching user by email
     * @param String $email User email id
     */
    public function getUserByEmail($email) {
        $stmt = $this->conn->prepare("SELECT user_id, name, email, created_at FROM users WHERE email = ?");
        $stmt->bind_param("s", $email);
        if ($stmt->execute()) {
            // $user = $stmt->get_result()->fetch_assoc();
            $stmt->bind_result($user_id, $name, $email, $created_at);
            $stmt->fetch();
            $user = array();
            $user["user_id"] = $user_id;
            $user["name"] = $name;
            $user["email"] = $email;
            $user["created_at"] = $created_at;
            $stmt->close();
            return $user;
        } else {
            return NULL;
        }
    }

}

?>

8. Now let’s start creating the files required for GCM. Create a file named gcm.php inside libs ⇒ gcm folder. This file contains necessary functions required to interact with GCM server. These functions basically makes a CURL request to GCM server by passing required parameters in order to invoke a push notification.

send() – Function sends push notification to a single user

sendToTopic() – Sends push notification to a topic

sendToMultiple() – Send push notification to multiple users

<?php
class GCM {

    // constructor
    function __construct() {
        
    }

    // sending push message to single user by gcm registration id
    public function send($to, $message) {
        $fields = array(
            'to' => $to,
            'data' => $message,
        );
        return $this->sendPushNotification($fields);
    }

    // Sending message to a topic by topic id
    public function sendToTopic($to, $message) {
        $fields = array(
            'to' => '/topics/' . $to,
            'data' => $message,
        );
        return $this->sendPushNotification($fields);
    }

    // sending push message to multiple users by gcm registration ids
    public function sendMultiple($registration_ids, $message) {
        $fields = array(
            'registration_ids' => $registration_ids,
            'data' => $message,
        );

        return $this->sendPushNotification($fields);
    }

    // function makes curl request to gcm servers
    private function sendPushNotification($fields) {

        // include config
        include_once __DIR__ . '/../../include/config.php';

        // Set POST variables
        $url = 'https://gcm-http.googleapis.com/gcm/send';

        $headers = array(
            'Authorization: key=' . GOOGLE_API_KEY,
            'Content-Type: application/json'
        );
        // Open connection
        $ch = curl_init();

        // Set the url, number of POST vars, POST data
        curl_setopt($ch, CURLOPT_URL, $url);

        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // Disabling SSL Certificate support temporarly
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));

        // Execute post
        $result = curl_exec($ch);
        if ($result === FALSE) {
            die('Curl failed: ' . curl_error($ch));
        }

        // Close connection
        curl_close($ch);

        return $result;
    }

}

?>

9. Under libs ⇒ gcm, create another file named push.php. This class prepares the required json format that is transferred as a push message to device. If you want to add additional fields to json, you need to add them in this class.

<?php
/**
 * @author Ravi Tamada
 * @link URL Tutorial link
 */

class Push{
    // push message title
    private $title;
    
    // push message payload
    private $data;
    
    // flag indicating background task on push received
    private $is_background;
    
    // flag to indicate the type of notification
    private $flag;
    
    function __construct() {
        
    }
    
    public function setTitle($title){
        $this->title = $title;
    }
    
    public function setData($data){
        $this->data = $data;
    }
    
    public function setIsBackground($is_background){
        $this->is_background = $is_background;
    }
    
    public function setFlag($flag){
        $this->flag = $flag;
    }
    
    public function getPush(){
        $res = array();
        $res['title'] = $this->title;
        $res['is_background'] = $this->is_background;
        $res['flag'] = $this->flag;
        $res['data'] = $this->data;
        
        return $res;
    }
}

10. At this stage, we have all the necessary functions ready. Let’s start preparing the REST API endpoints for the android app. Create a file named .htaccess inside v1 folder and add below rules.

RewriteEngine On 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule ^(.*)$ %{ENV:BASE}index.php [QSA,L]

11. Create index.php inside v1 folder. All the rest api requests will be handled by this file only.

<?php

error_reporting(-1);
ini_set('display_errors', 'On');

require_once '../include/db_handler.php';
require '.././libs/Slim/Slim.php';

\Slim\Slim::registerAutoloader();

$app = new \Slim\Slim();

// User login
$app->post('/user/login', function() use ($app) {
    // check for required params
    verifyRequiredParams(array('name', 'email'));

    // reading post params
    $name = $app->request->post('name');
    $email = $app->request->post('email');

    // validating email address
    validateEmail($email);

    $db = new DbHandler();
    $response = $db->createUser($name, $email);

    // echo json response
    echoRespnse(200, $response);
});


/* * *
 * Updating user
 *  we use this url to update user's gcm registration id
 */
$app->put('/user/:id', function($user_id) use ($app) {
    global $app;

    verifyRequiredParams(array('gcm_registration_id'));

    $gcm_registration_id = $app->request->put('gcm_registration_id');

    $db = new DbHandler();
    $response = $db->updateGcmID($user_id, $gcm_registration_id);

    echoRespnse(200, $response);
});

/* * *
 * fetching all chat rooms
 */
$app->get('/chat_rooms', function() {
    $response = array();
    $db = new DbHandler();

    // fetching all user tasks
    $result = $db->getAllChatrooms();

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

    // pushing single chat room into array
    while ($chat_room = $result->fetch_assoc()) {
        $tmp = array();
        $tmp["chat_room_id"] = $chat_room["chat_room_id"];
        $tmp["name"] = $chat_room["name"];
        $tmp["created_at"] = $chat_room["created_at"];
        array_push($response["chat_rooms"], $tmp);
    }

    echoRespnse(200, $response);
});

/**
 * Messaging in a chat room
 * Will send push notification using Topic Messaging
 *  */
$app->post('/chat_rooms/:id/message', function($chat_room_id) {
    global $app;
    $db = new DbHandler();

    verifyRequiredParams(array('user_id', 'message'));

    $user_id = $app->request->post('user_id');
    $message = $app->request->post('message');

    $response = $db->addMessage($user_id, $chat_room_id, $message);

    if ($response['error'] == false) {
        require_once __DIR__ . '/../libs/gcm/gcm.php';
        require_once __DIR__ . '/../libs/gcm/push.php';
        $gcm = new GCM();
        $push = new Push();

        // get the user using userid
        $user = $db->getUser($user_id);

        $data = array();
        $data['user'] = $user;
        $data['message'] = $response['message'];
        $data['chat_room_id'] = $chat_room_id;

        $push->setTitle("Google Cloud Messaging");
        $push->setIsBackground(FALSE);
        $push->setFlag(PUSH_FLAG_CHATROOM);
        $push->setData($data);
        
        // echo json_encode($push->getPush());exit;

        // sending push message to a topic
        $gcm->sendToTopic('topic_' . $chat_room_id, $push->getPush());

        $response['user'] = $user;
        $response['error'] = false;
    }

    echoRespnse(200, $response);
});


/**
 * Sending push notification to a single user
 * We use user's gcm registration id to send the message
 * * */
$app->post('/users/:id/message', function($to_user_id) {
    global $app;
    $db = new DbHandler();

    verifyRequiredParams(array('message'));

    $from_user_id = $app->request->post('user_id');
    $message = $app->request->post('message');

    $response = $db->addMessage($from_user_id, $to_user_id, $message);

    if ($response['error'] == false) {
        require_once __DIR__ . '/../libs/gcm/gcm.php';
        require_once __DIR__ . '/../libs/gcm/push.php';
        $gcm = new GCM();
        $push = new Push();

        $user = $db->getUser($to_user_id);

        $data = array();
        $data['user'] = $user;
        $data['message'] = $response['message'];
        $data['image'] = '';

        $push->setTitle("Google Cloud Messaging");
        $push->setIsBackground(FALSE);
        $push->setFlag(PUSH_FLAG_USER);
        $push->setData($data);

        // sending push message to single user
        $gcm->send($user['gcm_registration_id'], $push->getPush());

        $response['user'] = $user;
        $response['error'] = false;
    }

    echoRespnse(200, $response);
});


/**
 * Sending push notification to multiple users
 * We use gcm registration ids to send notification message
 * At max you can send message to 1000 recipients
 * * */
$app->post('/users/message', function() use ($app) {

    $response = array();
    verifyRequiredParams(array('user_id', 'to', 'message'));

    require_once __DIR__ . '/../libs/gcm/gcm.php';
    require_once __DIR__ . '/../libs/gcm/push.php';

    $db = new DbHandler();

    $user_id = $app->request->post('user_id');
    $to_user_ids = array_filter(explode(',', $app->request->post('to')));
    $message = $app->request->post('message');

    $user = $db->getUser($user_id);
    $users = $db->getUsers($to_user_ids);

    $registration_ids = array();

    // preparing gcm registration ids array
    foreach ($users as $u) {
        array_push($registration_ids, $u['gcm_registration_id']);
    }

    // insert messages in db
    // send push to multiple users
    $gcm = new GCM();
    $push = new Push();

    // creating tmp message, skipping database insertion
    $msg = array();
    $msg['message'] = $message;
    $msg['message_id'] = '';
    $msg['chat_room_id'] = '';
    $msg['created_at'] = date('Y-m-d G:i:s');

    $data = array();
    $data['user'] = $user;
    $data['message'] = $msg;
    $data['image'] = '';

    $push->setTitle("Google Cloud Messaging");
    $push->setIsBackground(FALSE);
    $push->setFlag(PUSH_FLAG_USER);
    $push->setData($data);

    // sending push message to multiple users
    $gcm->sendMultiple($registration_ids, $push->getPush());

    $response['error'] = false;

    echoRespnse(200, $response);
});

$app->post('/users/send_to_all', function() use ($app) {

    $response = array();
    verifyRequiredParams(array('user_id', 'message'));

    require_once __DIR__ . '/../libs/gcm/gcm.php';
    require_once __DIR__ . '/../libs/gcm/push.php';

    $db = new DbHandler();

    $user_id = $app->request->post('user_id');
    $message = $app->request->post('message');

    require_once __DIR__ . '/../libs/gcm/gcm.php';
    require_once __DIR__ . '/../libs/gcm/push.php';
    $gcm = new GCM();
    $push = new Push();

    // get the user using userid
    $user = $db->getUser($user_id);
    
    // creating tmp message, skipping database insertion
    $msg = array();
    $msg['message'] = $message;
    $msg['message_id'] = '';
    $msg['chat_room_id'] = '';
    $msg['created_at'] = date('Y-m-d G:i:s');

    $data = array();
    $data['user'] = $user;
    $data['message'] = $msg;
    $data['image'] = 'http://www.androidhive.info/wp-content/uploads/2016/01/Air-1.png';

    $push->setTitle("Google Cloud Messaging");
    $push->setIsBackground(FALSE);
    $push->setFlag(PUSH_FLAG_USER);
    $push->setData($data);

    // sending message to topic `global`
    // On the device every user should subscribe to `global` topic
    $gcm->sendToTopic('global', $push->getPush());

    $response['user'] = $user;
    $response['error'] = false;

    echoRespnse(200, $response);
});

/**
 * Fetching single chat room including all the chat messages
 *  */
$app->get('/chat_rooms/:id', function($chat_room_id) {
    global $app;
    $db = new DbHandler();

    $result = $db->getChatRoom($chat_room_id);

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

    $i = 0;
    // looping through result and preparing tasks array
    while ($chat_room = $result->fetch_assoc()) {
        // adding chat room node
        if ($i == 0) {
            $tmp = array();
            $tmp["chat_room_id"] = $chat_room["chat_room_id"];
            $tmp["name"] = $chat_room["name"];
            $tmp["created_at"] = $chat_room["chat_room_created_at"];
            $response['chat_room'] = $tmp;
        }

        if ($chat_room['user_id'] != NULL) {
            // message node
            $cmt = array();
            $cmt["message"] = $chat_room["message"];
            $cmt["message_id"] = $chat_room["message_id"];
            $cmt["created_at"] = $chat_room["created_at"];

            // user node
            $user = array();
            $user['user_id'] = $chat_room['user_id'];
            $user['username'] = $chat_room['username'];
            $cmt['user'] = $user;

            array_push($response["messages"], $cmt);
        }
    }

    echoRespnse(200, $response);
});

/**
 * Verifying required params posted or not
 */
function verifyRequiredParams($required_fields) {
    $error = false;
    $error_fields = "";
    $request_params = array();
    $request_params = $_REQUEST;
    // Handling PUT request params
    if ($_SERVER['REQUEST_METHOD'] == 'PUT') {
        $app = \Slim\Slim::getInstance();
        parse_str($app->request()->getBody(), $request_params);
    }
    foreach ($required_fields as $field) {
        if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) {
            $error = true;
            $error_fields .= $field . ', ';
        }
    }

    if ($error) {
        // Required field(s) are missing or empty
        // echo error json and stop the app
        $response = array();
        $app = \Slim\Slim::getInstance();
        $response["error"] = true;
        $response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty';
        echoRespnse(400, $response);
        $app->stop();
    }
}

/**
 * Validating email address
 */
function validateEmail($email) {
    $app = \Slim\Slim::getInstance();
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $response["error"] = true;
        $response["message"] = 'Email address is not valid';
        echoRespnse(400, $response);
        $app->stop();
    }
}

function IsNullOrEmptyString($str) {
    return (!isset($str) || trim($str) === '');
}

/**
 * Echoing json response to client
 * @param String $status_code Http response code
 * @param Int $response Json response
 */
function echoRespnse($status_code, $response) {
    $app = \Slim\Slim::getInstance();
    // Http response code
    $app->status($status_code);

    // setting response content type to json
    $app->contentType('application/json');

    echo json_encode($response);
}

$app->run();
?>

REST API Endpoints

The index.php inside v1 folder providers the below endpoints.

Base URL: http://localhost/gcm_chat/v1

EndpointParamsMethodDescription
/user/loginname, emailPOSTUser login or registration
/user/:idgcm_registration_idPUTUpdates user’s gcm registration id in database
/chat_roomsGETFetches all chat rooms
/chat_rooms/:idreplace :id with actual chat room idGETFetches single chat room messages
/chat_rooms/:id/messagereplace :id with actual chat room idPOSTPosting a message in a chat room
/users/:id/messagereplace :id with actual user idPOSTSending a message to user
/users/messageuser_id, to, message
`to` – param is user ids separated by comma (,)
POSTSending a message to multiple users
/users/send_to_alluser_id, messagePOSTSending a message to all the users subscribed to `global` topic

6. Testing the REST API

Before starting the android project, make sure that the php project is running without any errors. Follow the below steps to test the API.

1. Enable apache mod_rewrite module (link)

2. Enable curl extension. This allows php to make http requests from the backend (link).

3. Install Postman Chrome REST API extension. You can use any other rest api clients too.

The below video takes you through testing the API using Postman.

7. Building the Admin Panel

I created very simple admin panel using PHP, HTML, CSS & jQuery. This admin panel might not be used in production stage, but gives you necessary functions to build a better one.

1. Create a file named demo.php in the root directory of gcm_chat. This class contains function for the admin panel.

<?php

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

    private $conn;

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

    public function getAllChatRooms() {
        $stmt = $this->conn->prepare("SELECT * FROM chat_rooms");
        $stmt->execute();
        $tasks = $stmt->get_result();
        $stmt->close();
        return $tasks;
    }

    public function getAllUsers() {
        $stmt = $this->conn->prepare("SELECT * FROM users");
        $stmt->execute();
        $tasks = $stmt->get_result();
        $stmt->close();
        return $tasks;
    }

    public function getDemoUser() {
        $name = 'AndroidHive';
        $email = 'admin@androidhive.info';
        
        $stmt = $this->conn->prepare("SELECT user_id from users WHERE email = ?");
        $stmt->bind_param("s", $email);
        $stmt->execute();
        $stmt->store_result();
        $num_rows = $stmt->num_rows;
        if ($num_rows > 0) {
            $stmt->bind_result($user_id);
            $stmt->fetch();
            return $user_id;
        } else {
            $stmt = $this->conn->prepare("INSERT INTO users(name, email) values(?, ?)");
            $stmt->bind_param("ss", $name, $email);
            $result = $stmt->execute();
            $user_id = $stmt->insert_id;
            $stmt->close();
            return $user_id;
        }
    }
}
?>

2. Create a style sheet named style.css in the root directory.

/* 
    Created on : 22 Jan, 2016, 10:12:06 PM
    Author     : Ravi Tamada
*/

body{
    width: 100%;
    margin: 0;
    padding: 0;   
    font-family: 'Raleway', sans-serif;
}
.container_body{
    width: 1000px;
    margin: 0 auto;
}
.header{
    padding: 100px 0;
    text-align: center;
    color: #fff;
    background: -moz-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* ff3.6+ */
    background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, rgba(227,71,73,1)), color-stop(100%, rgba(186,27,31,1))); /* safari4+,chrome */
    background:-webkit-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* safari5.1+,chrome10+ */
    background: -o-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* opera 11.10+ */
    background: -ms-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* ie10+ */
    background:radial-gradient(ellipse at center, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* w3c */
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e34749', endColorstr='#ba1b1f',GradientType=1 ); /* ie6-9 */
}
.header .logo{
    font-weight: bold;
    font-size: 30px;
    display: block;
    margin: 10px 0;
    letter-spacing: 3px;
}
.header h2{
    display: block;
    font-size: 50px;
    font-weight: 100;
    line-height: 10px;
}
.header h2.small{
    font-size: 25px;
    font-weight: 300;
    padding-top: 20px;
    letter-spacing: 1px;
}
.topics{
    text-align: center;
    padding-top: 50px;
}
.topics h2.heading{
    font-size: 30px;
    color: #666;
    font-weight: 400;
    display: block;
}
.box{
    width: 900px;
    margin: 40px auto;
    border: 1px solid #dedede;
    background: #f2f4f8;
    position: relative;
}
.box .usr_container,
.box .msg_container{
    float: left;
    height: 600px;
    overflow-x: hidden;
    overflow-y: auto;
}
.box .usr_container{
    width: 350px;
    border-right: 1px solid #dedede;
    background: #fff;
}
.box .msg_container{
    width: 548px;
    position: relative;
}
.box ul{
    margin: 0;
    padding: 0;
}
.box ul li{
    margin: 0;
    padding: 0;
    list-style: none;
    text-align: left;
    cursor: pointer;
}

.box .usr_container ul li{
    padding: 20px 10px;
    background: #fff;
    border-bottom: 1px solid #dedede;
}
.box .usr_container ul li label{
    display: block;
    width: 100%;
    font-family: arial;
    font-weight: 400;
    color: #333;
    font-size: 18px;
    margin-bottom: 5px;
}
.box .usr_container ul li label:hover{
    cursor: pointer;
}
.box .usr_container ul li span{
    color: #777;
    font-family: arial;
    font-size: 14px;
    font-style: italic;
}
.box .usr_container ul li.selected{
    background: #f2f4f8;
}
.box .usr_container ul li.selected label{
    color: #e34749;
}
.box .usr_container ul li.selected span{
    color: #000;
}
.box .usr_container ul li:hover{
    background: #dedede;
    cursor: pointer;
}
.box .msg_container ul{
    padding: 10px 0;
    margin-bottom: 75px;
}
.box .msg_container li{
    padding: 10px 0;
}
.box .msg_container li.others{
    cursor: auto;
    text-align: left;
    padding-left: 20px;
}
.box .msg_container li.self{
    text-align: right;
    cursor: auto;
    padding-right: 20px;
}
.box .msg_container li.self label{
    float: right;
}
.box .msg_container li .message{
    background: #fff;
    border-radius: 3px;
    padding: 15px;
    max-width: 400px;
    font-size: 15px;
    font-family: arial;
    float: left;
    line-height: 20px;
    margin: 5px 0 10px 0;
}
.box .msg_container li label{
    float: left;
    display: block;
    width: 100%;
    font-size: 12px;
    color: #777;
    font-family: arial;
}
.box .msg_container li.others .message{

}
.box .msg_container li.self .message{
    background: #dee2ef;
    float: right;
    display: inline-block;
}
.clear{
    clear:both;
}
.send_container{
    border-top: 1px solid #dedede;
    background: #f7f9fd;
    position: absolute;
    bottom: 0;
    height:75px;
    right: 0;
}
.send_container textarea{
    background: #f7f9fd;
    height: 30px;
    width: 550px;
    font-size: 15px;
    text-align: left;
    padding: 20px;
    border: none;
    resize: none;
    outline: none;
}
.send_container input[type="button"]{
    position: absolute;
    top: 20px;
    right: 20px;
    padding: 10px;
    background: #e34749;
    outline: none;
    border: none;
    cursor: pointer;
    color: #fff;
    font-weight: bold;
    font-size: 15px;
}
.btn_send{
    padding: 10px;
    background: #e34749;
    outline: none;
    border: none;
    cursor: pointer;
    color: #fff;
    font-weight: bold;
    font-size: 15px;
}
.box .msg_container li label.name{
    display: block;
}
div.container{
    width: 900px;
    margin: 0 auto;
}
select.select_single{
    padding: 10px;
    font-size: 16px;
    width: 400px;
}
select.select_single option{
    font-size: 19px;
}
select.select_multiple{
    font-size: 15px;
    width: 400px;
    height: 200px;
}
select.select_multiple option{
    padding: 5px;
}
textarea.textarea_msg{
    width: 400px;
    height: 120px;
    resize: none;
    margin:20px auto;
    padding: 15px;
    background: #f7f9fd;
    font-size: 15px;
}
.loader{
    display: none;
}
pre{
    width: 800px;
    text-align: left !important;
    font-size: 16px;
    font-family: monospace;
    margin: 0 auto;
    line-height: 20px;
}
.separator{
    width: 100%;
    height: 1px;
    background: #cdcdcd;
    margin: 50px 0;
}

3. Paste the loader.gif image in the same directory.

4. Create index.php in the root directory. Here I have written necessary php, html and jQuery code to build the admin UI.

<?php
error_reporting(-1);
ini_set('display_errors', 'On');
?>

<?php
require_once __DIR__ . '/demo.php';
$demo = new Demo();
$admin_id = $demo->getDemoUser();
?>

<html>
    <head>
        <title>Google Cloud Messaging 3.0 | AndroidHive</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href='https://fonts.googleapis.com/css?family=Raleway:400,800,100' rel='stylesheet' type='text/css'>
        <link href='style.css' rel='stylesheet' type='text/css'>
        <link href='http://api.androidhive.info/gcm/styles/default.css' rel='stylesheet' type='text/css'>
        <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
        <script type="text/javascript">
            var user_id = '<?= $admin_id ?>';
            $(document).ready(function () {

                getChatroomMessages($('#topics li:first').attr('id'));


                $('ul#topics li').on('click', function () {
                    $('ul#topics li').removeClass('selected');
                    $(this).addClass('selected');
                    getChatroomMessages($(this).prop('id'))
                });

                function getChatroomMessages(id) {
                    $.getJSON("v1/chat_rooms/" + id, function (data) {
                        var li = '';
                        $.each(data.messages, function (i, message) {
                            li += '<li class="others"><label class="name">' + message.user.username + '</label><div class="message">' + message.message + '</div><div class="clear"></div></li>';
                        });
                        $('ul#topic_messages').html(li);
                        if (data.messages.length > 0) {
                            scrollToBottom('msg_container_topic');
                        }
                    }).done(function () {

                    }).fail(function () {
                        alert('Sorry! Unable to fetch topic messages');
                    }).always(function () {

                    });

                    // attaching the chatroom id to send button
                    $('#send_to_topic').attr('chat_room', id);
                }

                $('#send_to_topic').on('click', function () {
                    var msg = $('#send_to_topic_message').val();
                    if (msg.trim().length === 0) {
                        alert('Enter a message');
                        return;
                    }

                    $('#send_to_topic_message').val('');
                    $('#loader_topic').show();

                    $.post("v1/chat_rooms/" + $(this).attr('chat_room') + '/message',
                            {user_id: user_id, message: msg},
                    function (data) {
                        if (data.error === false) {
                            var li = '<li class="self" tabindex="1"><label class="name">' + data.user.name + '</label><div class="message">' + data.message.message + '</div><div class="clear"></div></li>';
                            $('ul#topic_messages').append(li);
                            scrollToBottom('msg_container_topic');
                        } else {
                            alert('Sorry! Unable to send message');
                        }
                    }).done(function () {

                    }).fail(function () {
                        alert('Sorry! Unable to send message');
                    }).always(function () {
                        $('#loader_topic').hide();
                    });
                });

                $('input#send_to_single_user').on('click', function () {
                    var msg = $('#send_to_single').val();
                    var to = $('.select_single').val();
                    if (msg.trim().length === 0) {
                        alert('Enter a message');
                        return;
                    }

                    $('#send_to_single').val('');
                    $('#loader_single').show();

                    $.post("v1/users/" + to + '/message',
                            {user_id: user_id, message: msg},
                    function (data) {
                        if (data.error === false) {
                            $('#loader_single').hide();
                            alert('Push notification sent successfully! You should see a Toast message on device.');
                        } else {
                            alert('Sorry! Unable to post message');
                        }
                    }).done(function () {

                    }).fail(function () {
                        alert('Sorry! Unable to send message');
                    }).always(function () {
                        $('#loader_single').hide();
                    });
                });

                $('input#send_to_multiple_users').on('click', function () {
                    var msg = $('#send_to_multiple').val();
                    var to = $('.select_multiple').val();

                    if (to === null) {
                        alert("Please select the users!");
                        return;
                    }

                    if (msg.trim().length === 0) {
                        alert('Enter a message');
                        return;
                    }

                    $('#send_to_multiple').val('');
                    $('#loader_multiple').show();

                    var selMulti = $.map($(".select_multiple option:selected"), function (el, i) {
                        return $(el).val();
                    });

                    to = selMulti.join(",");

                    $.post("v1/users/message",
                            {user_id: user_id, to: to, message: msg},
                    function (data) {
                        if (data.error === false) {
                            $('#loader_multiple').hide();
                            alert('Push notification sent successfully to multiple users');
                        } else {
                            alert('Sorry! Unable to send message');
                        }
                    }).done(function () {

                    }).fail(function () {
                        alert('Sorry! Unable to send message');
                    }).always(function () {
                        $('#loader_multiple').hide();
                    });
                });

                $('input#send_to_multiple_users_with_image').on('click', function () {

                    var msg = $('#send_to_multiple_with_image').val();
                    if (msg.trim().length === 0) {
                        alert('Enter a message');
                        return;
                    }

                    $('#send_to_multiple_with_image').val('');
                    $('#loader_multiple_with_image').show();

                    $.post("v1/users/send_to_all",
                            {user_id: user_id, message: msg},
                    function (data) {
                        if (data.error === false) {
                            $('#loader_multiple_with_image').hide();
                            alert('Push notification sent successfully to multiple users');
                        } else {
                            alert('Sorry! Unable to send message');
                        }
                    }).done(function () {

                    }).fail(function () {
                        alert('Sorry! Unable to send message');
                    }).always(function () {
                        $('#loader_topic_with_image').hide();
                    });
                });

                function scrollToBottom(cls) {
                    $('.' + cls).scrollTop($('.' + cls + ' ul li').last().position().top + $('.' + cls + ' ul li').last().height());
                }
            });
        </script>
    </head>
    <body>
        <div class="header">
            <label class="logo">ANDROIDHIVE</label>
            <h2>Google Cloud Messaging</h2>
            <h2 class="small">Sending push notifications using Android, PHP & MySQL</h2>
        </div>
        <div class="container_body">
            <div class="topics">
                <h2 class="heading">Download & Install the GCM apk</h2>
                Download & Install the Google Cloud Messaging <a href="#">apk</a> before trying the demos. <br/><br/>Once installed, refresh this page 
                to see your name, email in the recipients list.
            </div>

            <div class="topics">
                <div class="separator"></div>
                <h2 class="heading">Sending message to a `topic`</h2>
                Select any of the topics below and send a message.<br/><br/>
                <div class="box">
                    <div class="usr_container">
                        <ul id="topics">
                            <?php
                            $chatrooms = $demo->getAllChatRooms();
                            foreach ($chatrooms as $key => $chatroom) {
                                $cls = $key == 0 ? 'selected' : '';
                                ?>
                                <li id="<?= $chatroom['chat_room_id'] ?>" class="<?= $cls ?>">
                                    <label><?= $chatroom['name'] ?></label>
                                    <span>topic_<?= $chatroom['chat_room_id'] ?></span>
                                </li>
                                <?php
                            }
                            ?>
                        </ul>
                    </div>
                    <div class="msg_container msg_container_topic">
                        <ul id="topic_messages"></ul>
                    </div>
                    <div class="send_container">
                        <textarea placeholder="Type a message here" id="send_to_topic_message"></textarea>
                        <input id="send_to_topic" type="button" value="Send to Topic"/>
                        <img src="loader.gif" id="loader_topic" class="loader"/>
                    </div>
                    <div class="clear"></div>
                </div>
                <br/>
                <div class="separator"></div>
                <h2 class="heading">Sending message to `Single User`</h2>
                Select your name from the below recipients and send a message<br/><br/>

                <div class="container">
                    <select class="select_single">
                        <?php
                        $users = $demo->getAllUsers();
                        foreach ($users as $key => $user) {
                            ?>
                            <option value="<?= $user['user_id'] ?>"><?= $user['name'] ?> (<?= $user['email'] ?>)</option>
                            <?php
                        }
                        ?>
                    </select><br/>
                    <textarea id="send_to_single" class="textarea_msg" placeholder="Type a message"></textarea><br/>
                    <input id="send_to_single_user" type="button" value="Send to single user" class="btn_send"/>
                    <img src="loader.gif" id="loader_single" class="loader"/>
                </div>
                <br/>
                <div class="separator"></div>
                <h2 class="heading">Sending message to `Multiple Users`</h2>
                Select multiple recipients and send a message. You can use ctrl or shift to select multiple users<br/><br/><br/>

                <div class="container">
                    <select multiple class="select_multiple">
                        <?php
                        foreach ($users as $key => $user) {
                            ?>
                            <option value="<?= $user['user_id'] ?>"><?= $user['name'] ?> (<?= $user['email'] ?>)</option>
                            <?php
                        }
                        ?>
                    </select>
                    <br/>
                    <textarea id="send_to_multiple" class="textarea_msg" placeholder="Type a message"></textarea><br/>
                    <input id="send_to_multiple_users" type="button" value="Send to multiple users" class="btn_send"/>
                    <img src="loader.gif" id="loader_multiple" class="loader"/>
                </div>

                <br/>
                <div class="separator"></div>
                <h2 class="heading">Sending push notification with an `Image`</h2>
                A message with an image attachment will be sent to every user. You have to minimize or close the app in order to see
                it in action.<br/><br/>

                <div class="container">
                    <textarea id="send_to_multiple_with_image" class="textarea_msg" placeholder="Type a message"></textarea><br/>
                    <input id="send_to_multiple_users_with_image" type="button" value="Send with image" class="btn_send"/>
                    <img src="loader.gif" id="loader_multiple_with_image" class="loader"/>
                </div>
            </div>
            <br/><br/>
            <br/><br/>
            <br/><br/>
        </div>
    </body>
</html>

5. Finally access the admin panel by going to http://localhost/gcm_chat/ (If your apache is running under a port, add the port number to localhost)

You should able to see the below admin panel which provides options to send the messages to devices from admin panel. Here the Live Demo of the admin app.

android-gcm-chat-app-admin-panel

With this we have completed 1s part of the article, but before moving to 2nd Part, quickly go through below code snippets which are very useful if you want to extend the server app functionality.

7. Quick Code Snippets

Sending Push To Single User

        require_once __DIR__ . '/../libs/gcm/gcm.php';
        require_once __DIR__ . '/../libs/gcm/push.php';
        $gcm = new GCM();
        $push = new Push();

        $data = array();
        // user node
        $data['user'] = $user;
        // message node
        $data['message'] = $response['message'];
        $data['image'] = '';

        $push->setTitle("Google Cloud Messaging");
        $push->setIsBackground(FALSE);
        $push->setFlag(PUSH_FLAG_USER);
        $push->setData($data);

        // Pass the receiver gcm registration token
        $gcm_registration_id = 'fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....';

        // sending push message to single user
        $gcm->send($user['gcm_registration_id'], $push->getPush());

Sending Push To Multiple Users

    require_once __DIR__ . '/../libs/gcm/gcm.php';
    require_once __DIR__ . '/../libs/gcm/push.php';

    $gcm = new GCM();
    $push = new Push();

    $msg = array();
    $msg['message'] = $message;
    $msg['message_id'] = '';
    $msg['chat_room_id'] = '';
    $msg['created_at'] = date('Y-m-d G:i:s');

    $data = array();
    $data['user'] = $user;
    $data['message'] = $msg;
    $data['image'] = '';

    $push->setTitle("Google Cloud Messaging");
    $push->setIsBackground(FALSE);
    $push->setFlag(PUSH_FLAG_USER);
    $push->setData($data);

    // Keep all the recipients gcm tokens in an array 
    $registration_ids = array('fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....', 'fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....');

    // sending push message to multiple users
    $gcm->sendMultiple($registration_ids, $push->getPush());

Sending Push To a Topic

        require_once __DIR__ . '/../libs/gcm/gcm.php';
        require_once __DIR__ . '/../libs/gcm/push.php';

        $gcm = new GCM();
        $push = new Push();

        $data = array();
        $data['user'] = $user;
        $data['message'] = $response['message'];
        $data['chat_room_id'] = $chat_room_id;

        $push->setTitle("Google Cloud Messaging");
        $push->setIsBackground(FALSE);
        $push->setFlag(PUSH_FLAG_CHATROOM);
        $push->setData($data);

        // the topic you want to send notification
        $topic = 'your_topic_name';

        // sending push message to a topic
        $gcm->sendToTopic($topic, $push->getPush());

Sending Push with an Image

        require_once __DIR__ . '/../libs/gcm/gcm.php';
        require_once __DIR__ . '/../libs/gcm/push.php';

        $gcm = new GCM();
        $push = new Push();

        // keep the notification image url here
        $image = 'http://api.androidhive.info/gcm/panda.jpg';

        $data = array();
        $data['user'] = $user;
        $data['message'] = $response['message'];
        $data['image'] = $image;

        $push->setTitle("Google Cloud Messaging");
        $push->setIsBackground(FALSE);
        $push->setFlag(PUSH_FLAG_USER);
        $push->setData($data);

        $gcm_registration_id = 'fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....';

        // sending push message to single user
        $gcm->send($user['gcm_registration_id'], $push->getPush());

By far we have successfully built the proper REST API client and a simple admin panel. Now let’s start building the android app in 2nd Part. If you are facing any issue in this part, please comment in below discussions.