My previous article gives you an understanding of how to develop any application using RESTful APIs. But, mere implementation of API is not enough for making it more effective. It requires a proper authentication and more security. Here is the article for a secured RESTful API on a token basis. An encrypted token, which is generated based on your site id and ip address is sent with the request call; this token is then be used to authenticate to use a RESTful service in your application. Follow the demo below for your reference.

The tutorial contains three folders called restful, js and css with PHP files.
restful
-- Slim // Slim Framework
---- db.php
---- index.php // api index file
---- .htaccess // url redirection file.
js
-- jquery.min.js
-- ajaxGetPost.js
css
-- style.css
index.php
-- Slim // Slim Framework
---- db.php
---- index.php // api index file
---- .htaccess // url redirection file.
js
-- jquery.min.js
-- ajaxGetPost.js
css
-- style.css
index.php
Database Design
To build the friend updates system, you have to create three tables such as Users, Friends and Updates. You can check my previous tutorials for friend system.
Users Table
User table contains all the users registration details.
CREATE TABLE `users` (
`user_id` int(11) AUTO_INCREMENT,
`username` varchar(50),
`password` varchar(100),
`name` varchar(100),
`profile_pic` varchar(200),
PRIMARY KEY (`user_id`)
);
`user_id` int(11) AUTO_INCREMENT,
`username` varchar(50),
`password` varchar(100),
`name` varchar(100),
`profile_pic` varchar(200),
PRIMARY KEY (`user_id`)
);
Updates Table
User table contains user status update details.
CREATE TABLE `updates` (
`update_id` int(11) AUTO_INCREMENT,
`user_update` text,
`user_id_fk` int(11),
`created` int(11),
`ip` varchar(50),
PRIMARY KEY (`update_id`)
);
`update_id` int(11) AUTO_INCREMENT,
`user_update` text,
`user_id_fk` int(11),
`created` int(11),
`ip` varchar(50),
PRIMARY KEY (`update_id`)
);
Create a RESTful services using Slim PHP Framework
RESTful Web Services API using Java and MySQL
db.php
You have to modify database configuration details, before trying this enable php_pdo extension in php.ini file.
<?php
session_start();
$_SESSION['uid']='1';
$session_uid=$_SESSION['uid'];
define("SITE_KEY", "yoursitekey");
function getDB() {
$dbhost="localhost";
$dbuser="username";
$dbpass="password";
$dbname="database";
$dbConnection = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbConnection;
}
/* API key encryption */
function apiKey($session_uid)
{
$key=md5(SITE_KEY.$session_uid);
return hash('sha256', $key.$_SERVER['REMOTE_ADDR']);
}
$apiKey=apiKey($session_uid);
?>
session_start();
$_SESSION['uid']='1';
$session_uid=$_SESSION['uid'];
define("SITE_KEY", "yoursitekey");
function getDB() {
$dbhost="localhost";
$dbuser="username";
$dbpass="password";
$dbname="database";
$dbConnection = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbConnection;
}
/* API key encryption */
function apiKey($session_uid)
{
$key=md5(SITE_KEY.$session_uid);
return hash('sha256', $key.$_SERVER['REMOTE_ADDR']);
}
$apiKey=apiKey($session_uid);
?>
Slim Framework
api/index.php
Slim Framework helps you to implement API system simple.
<?php
require 'db.php';
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app->get('/userDetails','getUserDetails');
$app->get('/users','getUsers');
$app->post('/userUpdates','userUpdates');
$app->post('/insertUpdate', 'insertUpdate');
$app->delete('/updates/delete/:update_id/:user_id/:apiKey','deleteUpdate');
$app->get('/users/search/:query','getUserSearch');
$app->run();
// GET http://www.yourwebsite.com/api/users
function getUsers() {
.....
.....
}
function userUpdates()
{
$request = \Slim\Slim::getInstance()->request();
$update = json_decode($request->getBody());
$apiKey=$update->apiKey;
$sever_apiKey=apiKey($update->user_id);
$sql = "SELECT A.user_id, A.username, A.name, A.profile_pic, B.update_id, B.user_update, B.created FROM users A, updates B WHERE A.user_id=B.user_id_fk ORDER BY B.update_id DESC";
try {
if($apiKey == $sever_apiKey)
{
$db = getDB();
$stmt = $db->prepare($sql);
$stmt->execute();
$updates = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo '{"updates": ' . json_encode($updates) . '}';
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function getUserUpdate($update_id) {
.....
.....
}
function insertUpdate() {
$request = \Slim\Slim::getInstance()->request();
$update = json_decode($request->getBody());
$apiKey=$update->apiKey;
$sever_apiKey=apiKey($update->user_id);
$sql = "INSERT INTO updates (user_update, user_id_fk, created, ip) VALUES (:user_update, :user_id, :created, :ip)";
try {
if($apiKey == $sever_apiKey)
{
$db = getDB();
$stmt = $db->prepare($sql);
$stmt->bindParam("user_update", $update->user_update);
$stmt->bindParam("user_id", $update->user_id);
$time=time();
$stmt->bindParam("created", $time);
$ip=$_SERVER['REMOTE_ADDR'];
$stmt->bindParam("ip", $ip);
$stmt->execute();
$update->id = $db->lastInsertId();
$db = null;
$update_id= $update->id;
getUserUpdate($update_id);
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function deleteUpdate($update_id,$user_id,$apiKey)
{
$sever_apiKey=apiKey($user_id);
$sql = "DELETE FROM api_updates WHERE update_id=:update_id";
try {
if($apiKey == $sever_apiKey)
{
$db = getDB();
$stmt = $db->prepare($sql);
$stmt->bindParam("update_id", $update_id);
$stmt->execute();
$db = null;
echo true;
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function getUserUpdate($update_id) {
//.....
//.....
}
// GET http://www.yourwebsite.com/api/users/search/sri
function getUserSearch($query) {
//.....
//....
}
?>
require 'db.php';
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app->get('/userDetails','getUserDetails');
$app->get('/users','getUsers');
$app->post('/userUpdates','userUpdates');
$app->post('/insertUpdate', 'insertUpdate');
$app->delete('/updates/delete/:update_id/:user_id/:apiKey','deleteUpdate');
$app->get('/users/search/:query','getUserSearch');
$app->run();
// GET http://www.yourwebsite.com/api/users
function getUsers() {
.....
.....
}
function userUpdates()
{
$request = \Slim\Slim::getInstance()->request();
$update = json_decode($request->getBody());
$apiKey=$update->apiKey;
$sever_apiKey=apiKey($update->user_id);
$sql = "SELECT A.user_id, A.username, A.name, A.profile_pic, B.update_id, B.user_update, B.created FROM users A, updates B WHERE A.user_id=B.user_id_fk ORDER BY B.update_id DESC";
try {
if($apiKey == $sever_apiKey)
{
$db = getDB();
$stmt = $db->prepare($sql);
$stmt->execute();
$updates = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo '{"updates": ' . json_encode($updates) . '}';
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function getUserUpdate($update_id) {
.....
.....
}
function insertUpdate() {
$request = \Slim\Slim::getInstance()->request();
$update = json_decode($request->getBody());
$apiKey=$update->apiKey;
$sever_apiKey=apiKey($update->user_id);
$sql = "INSERT INTO updates (user_update, user_id_fk, created, ip) VALUES (:user_update, :user_id, :created, :ip)";
try {
if($apiKey == $sever_apiKey)
{
$db = getDB();
$stmt = $db->prepare($sql);
$stmt->bindParam("user_update", $update->user_update);
$stmt->bindParam("user_id", $update->user_id);
$time=time();
$stmt->bindParam("created", $time);
$ip=$_SERVER['REMOTE_ADDR'];
$stmt->bindParam("ip", $ip);
$stmt->execute();
$update->id = $db->lastInsertId();
$db = null;
$update_id= $update->id;
getUserUpdate($update_id);
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function deleteUpdate($update_id,$user_id,$apiKey)
{
$sever_apiKey=apiKey($user_id);
$sql = "DELETE FROM api_updates WHERE update_id=:update_id";
try {
if($apiKey == $sever_apiKey)
{
$db = getDB();
$stmt = $db->prepare($sql);
$stmt->bindParam("update_id", $update_id);
$stmt->execute();
$db = null;
echo true;
}
}
catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function getUserUpdate($update_id) {
//.....
//.....
}
// GET http://www.yourwebsite.com/api/users/search/sri
function getUserSearch($query) {
//.....
//....
}
?>
Chrome Extention
A Extention for testing PHP restful API response download here Advanced REST client Application
Cross Domain Access
A cross-domain system is transfer information/data between two or more differing domains. Eg. abc.com to xyz.com.htaccess
I did modified the Slim Framework default .htaccess code for cross domain support.
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
# RewriteBase /
# Cross domain access
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
# RewriteBase /
# Cross domain access
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
Learn more about Status Message Design with CSS
Jquery
Contains JavaScript and HTML code, using Jquery ajax parsing API data into HTML format.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="js/ajaxGetPost.js"></script>
<script>
$(document).ready(function()
{
var base_url="http://www.yourwebsite.com/project_name/";
var url,encodedata;
$("#update").focus();
/* Load Updates */
url=base_url+'api/updates';
ajax_data('GET',url, function(data)
{
$.each(data.updates, function(i,data)
{
var html="<div class='stbody' id='stbody"+data.update_id+"'><div class='stimg'><img src='"+data.profile_pic+"' class='stprofileimg'/></div><div class='sttext'><strong>"+data.name+"</strong>"+data.user_update+"<span id='"+data.update_id+"' class='stdelete'>Delete</span></div></div>";
$(html).appendTo("#mainContent");
});
});
/* Insert Update */
$('body').on("click",'.stpostbutton',function()
{
var update=$('#update').val();
encode=JSON.stringify({
"user_update": update,
"user_id": $('#user_id').val()
});
url=base_url+'api/updates';
if(update.length>0)
{
post_ajax_data(url,encode, function(data)
{
$.each(data.updates, function(i,data)
{
var html="<div class='stbody' id='stbody"+data.update_id+"'><div class='stimg'><img src='"+data.profile_pic+"' class='stprofileimg'/></div><div class='sttext'><strong>"+data.name+"</strong>"+data.user_update+"<span id='"+data.update_id+"' class='stdelete'>Delete</span></div></div>";
$("#mainContent").prepend(html);
$('#update').val('').focus();
});
});
}
});
/* Delete Updates */
$('body').on("click",'.stdelete',function()
{
var ID=$(this).attr("id");
url=base_url+'api/updates/delete/'+ID;
ajax_data('DELETE',url, function(data)
{
$("#stbody"+ID).fadeOut("slow");
});
});
});
</script>
<script src="js/ajaxGetPost.js"></script>
<script>
$(document).ready(function()
{
var base_url="http://www.yourwebsite.com/project_name/";
var url,encodedata;
$("#update").focus();
/* Load Updates */
url=base_url+'api/updates';
ajax_data('GET',url, function(data)
{
$.each(data.updates, function(i,data)
{
var html="<div class='stbody' id='stbody"+data.update_id+"'><div class='stimg'><img src='"+data.profile_pic+"' class='stprofileimg'/></div><div class='sttext'><strong>"+data.name+"</strong>"+data.user_update+"<span id='"+data.update_id+"' class='stdelete'>Delete</span></div></div>";
$(html).appendTo("#mainContent");
});
});
/* Insert Update */
$('body').on("click",'.stpostbutton',function()
{
var update=$('#update').val();
encode=JSON.stringify({
"user_update": update,
"user_id": $('#user_id').val()
});
url=base_url+'api/updates';
if(update.length>0)
{
post_ajax_data(url,encode, function(data)
{
$.each(data.updates, function(i,data)
{
var html="<div class='stbody' id='stbody"+data.update_id+"'><div class='stimg'><img src='"+data.profile_pic+"' class='stprofileimg'/></div><div class='sttext'><strong>"+data.name+"</strong>"+data.user_update+"<span id='"+data.update_id+"' class='stdelete'>Delete</span></div></div>";
$("#mainContent").prepend(html);
$('#update').val('').focus();
});
});
}
});
/* Delete Updates */
$('body').on("click",'.stdelete',function()
{
var ID=$(this).attr("id");
url=base_url+'api/updates/delete/'+ID;
ajax_data('DELETE',url, function(data)
{
$("#stbody"+ID).fadeOut("slow");
});
});
});
</script>

HTML Code
Contains HTML code. $("body").on('click','.stpostbutton', function(){}- stpostbutton is the ID name of the POST button. Using jquery stringify converting input data into JSON format.
<div>
<textarea id="update" class="stupdatebox"></textarea>
<input type="hidden" id="user_id" value="User Session Value">
<input type="submit" value="POST" class="stpostbutton">
</div>
<div id="mainContent"></div>
<textarea id="update" class="stupdatebox"></textarea>
<input type="hidden" id="user_id" value="User Session Value">
<input type="submit" value="POST" class="stpostbutton">
</div>
<div id="mainContent"></div>
ajaxGetPost.js
Jquery Post, Get and Delete Ajax functions.
//POST Ajax
function post_ajax_data(url, encodedata, success)
{
$.ajax({
type:"POST",
url:url,
data :encodedata,
dataType:"json",
restful:true,
contentType: 'application/json',
cache:false,
timeout:20000,
async:true,
beforeSend :function(data) { },
success:function(data){
success.call(this, data);
},
error:function(data){
alert("Error In Connecting");
}
});
}
//GET and DELETE Ajax
function ajax_data(type, url, success)
{
$.ajax({
type:type,
url:url,
dataType:"json",
restful:true,
cache:false,
timeout:20000,
async:true,
beforeSend :function(data) { },
success:function(data){
success.call(this, data);
},
error:function(data){
alert("Error In Connecting");
}
});
}
function post_ajax_data(url, encodedata, success)
{
$.ajax({
type:"POST",
url:url,
data :encodedata,
dataType:"json",
restful:true,
contentType: 'application/json',
cache:false,
timeout:20000,
async:true,
beforeSend :function(data) { },
success:function(data){
success.call(this, data);
},
error:function(data){
alert("Error In Connecting");
}
});
}
//GET and DELETE Ajax
function ajax_data(type, url, success)
{
$.ajax({
type:type,
url:url,
dataType:"json",
restful:true,
cache:false,
timeout:20000,
async:true,
beforeSend :function(data) { },
success:function(data){
success.call(this, data);
},
error:function(data){
alert("Error In Connecting");
}
});
}
slim framework version?
ReplyDeleteI believe it is slim 2.5
DeleteHave you tried slim 3.x? Do you have a 3.x example?
DeleteI am also looking for it :D
DeleteHi Srinivas,
ReplyDeleteArticle looks great & helpful :)
But one doubt, from where the client gets token for first api call?
But one doubt, from where the client gets token for first api call?
ReplyDeleteThanks Srinivas. But I don't understand why $session_uid used?
ReplyDeleteYou will get this $session_uid value after login success, read this article http://www.9lessons.info/2016/04/php-login-system-with-pdo-connection.html
DeleteHey Srinivas,All your tutorials are great, I am big fan of yours ,Here What i studied about Token Based Web services is that the tokens are stored in local storage so that when every time session updates, it does not need to request server , as it will make server slow , that's major reason we use token based authentication , And here to generate api_key, you used session_id ???
ReplyDeleteReally very useful tutorials you are posting srini, for learners easy to learn with your support.. tq so much
ReplyDeleteWhat is the value of define("SITE_KEY", "yoursitekey"); yoursitekey and where to get it from in this example?
ReplyDeleteAlso on requesting index.php Ajax spits ot "Error in connecting" db connection error? or what? My db is setup OK with correct access parameters set.
What is the value of define("SITE_KEY", "yoursitekey"); kindly clarify...
ReplyDeleteSITE_KEY is like a password, it adds extra security to generate token value.
DeleteI have add right path in .htaccess file but still i m getting 404 error for some url in your given code.kindly advice
ReplyDeleteA question, when trying the url "http: // localhost / PHP-Slim-Restful / api / singup" returns the following error
ReplyDelete404 Page Not Found
The page you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly. If all else fails, you can visit our home page at the link below
I am running the services of Apache and mysql and already look for a psible error and it seems that it does not find the url inside a predefined list of url's, but I do not understand well, apensas I am resuming PHP after 8 years, you could help me
Please try to access api urls with Chrome extension called Postman. API post request urls does not accessible directly.
DeleteHow to create SITE-KEY?
ReplyDeleteSite key is your password.
DeletePouvez-vous me donner la procédure pour créer le SITE-KEY. Merci
ReplyDeleteif i change SITE_KEY, tokens don't match.... How to create SITE_KEY? Thanks
ReplyDeletehi, Srivinas ... this tutorial is very help full, but somehow I am still stuck at building my first app, probably because I am using nodeJS, and have no knowledge about PHP. is there your article similiar to this but using nodeJS API, I thought that will be very helpful for me
ReplyDelete