use socket.io to bridge pooling php rest api - php

i have my php point exposing these endpoints for example
[GET] /api/news --> [return] [ {id:1,title:'news1'},{id:1,title:'news1'} ];
[POST] /api/news?title=<string> --> [return] {id:NEW_ID,title:$title};
and my frontend webapp use angular 1 to get news.
//to get all news
$http.get('http://server.com/api/news').then(function(res){
$scope.news = res.data;
});
//to post a new news
$http.post('http://server.com/api/news',{title:'news3'}).then(function(res){
$scope.news.push(res.data);
});
this would work fine, except that i will have to pool every interval to get any new news, so i thought something like socket.io can help.
I'm tryying to achive.
user connect to io
io send all news once user connects by consuming my php api
when user post new, he send it to io server, and io forward the post request to my rest api and return the result to all connected users.
so my change to front end can be something like
var socket = io('http://localhost:3700');
socket.on('news', function (data) {
$timeout(()=>{$scope.news = data;});
});
socket.on('news_posted', function (data) {
$timeout(()=>{$scope.news.push(data);});
});
$scope.post = function(title){
socket.emit('post_news', { title: title });
}
now what i have no clue is how to make such simple server ?
var express = require("express");
var app = express();
var port = 3700;
var io = require('socket.io').listen(app.listen(port));
//setting CORS
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8100");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key,auth-client,auth-uid,auth-token');
if (req.method == 'OPTIONS') {
res.status(200).end();
} else {
next();
}
});
io.sockets.on('connection', function (socket) {
console.log('a user connected');
///BLOCK 1
///GET ALL POSTS FROM API AND EMIT news event BACK TO USER
///
socket.on('new_post', function(msg){
///BLOCK 2
///POST title TO API AND EMIT BACK news_posted WITH THE RESPONSE
});
});

Related

Encrypt with flutter and php, decrypt with php and flutter

I have a chat application created using flutter dart and php mysql as backend and also node js for socket.io
So what i want is if i send a message via flutter dart, i want to encrypt it and send to node js via socket.io which will send it to the other client's flutter app and decrypt it there for the user to see and the node.js will also send it to my php script via json format and stores it in my database via post request. Also I will soon create a website where those messages will be decryted and displayed on the user browser and when i send message using the browser i also want to encrypt it and store in the database so that both flutter and web user can see the decrypted format.
const https = require("https");
const http = require("http");
const qs = require("querystring");
function send_to_db(msg) {
console.log(msg);
var postData = qs.stringify(msg);
var options = {
hostname: "*****.com",
port: 443,
path: "/src/chats/post.php",
method: "POST",
rejectUnauthorized: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": postData.length,
},
checkServerIdentity: function (host, cert) {
return undefined;
},
};
var buffer = "";
var req = https.request(options, (res) => {
res.on("data", function (chunk) {
buffer += chunk;
});
res.on("end", function () {
console.log(buffer);
});
});
req.on("error", (e) => {
console.error(e);
});
req.write(postData);
req.end();
return buffer;
}
Right now is am only encrypting and decrypting using php and am afraid of man in the middle attack since my data can be intercepted from flutter app to node.js before reaching my php side
Please what do I do to achieve this

Stripe Checkout PHP Causes mysterious 404 Error OnLoad

I'm having a hard time testing the Stripe Checkout from single-checkout-subscription on my local xampp server. So far, I have a Stripe account, created my test keys, product and prices, installed Stripe Cli and created a test webhook and added them all to the .env file in my server
DOMAIN="http://localhost/stripe/server/public/"
BASIC_PRICE_ID="price_xxx"
PRO_PRICE_ID="price_xxx"
STATIC_DIR="STATIC_DIR=../../client"
STRIPE_PUBLISHABLE_KEY="pk_test_xxx"
STRIPE_SECRET_KEY="sk_test_xxx"
STRIPE_WEBHOOK_SECRET="1mwhxxx"
But when I tested it at my local host: http://localhost/stripe/server/public/ I get the front end, but when I click on the button nothing happens. It doesn't even go to the prebuilt checkout page.
I check the console and the problems seems to becoming from my config.php
Two console errors appear on my script.js:
fetch("/config.php").then(function(json)
This is the routing:
My config.php > requires shared.php > requires '..vendor/autoload.php' & parses '../conifg/ini' > conifg.ini contains my test keys:
stripe_secret_key ="sk_test_444"
stripe_publishable_key = "pk_test_444"
stripe_webhook_secret = "1mw444"
domain = "http://localhost/stripe/server/public/"
basic_price_id = "price_444"
pro_price_id = "price_555"
Script.js inisde my server:
// Create a Checkout Session with the selected plan ID
var createCheckoutSession = function(priceId) {
return fetch("/create-checkout-session.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
priceId: priceId
})
}).then(function(result) {
return result.json();
});
};
// Handle any errors returned from Checkout
var handleResult = function(result) {
if (result.error) {
var displayError = document.getElementById("error-message");
displayError.textContent = result.error.message;
}
};
/* Get your Stripe publishable key to initialize Stripe.js */
fetch("/config.php")
.then(function(result) {
return result.json();
})
.then(function(json) {
var publishableKey = json.publishableKey;
var basicPriceId = json.basicPrice;
var proPriceId = json.proPrice;
var stripe = Stripe(publishableKey);
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("basic-plan-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(basicPriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("pro-plan-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(proPriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
});
I'm well versed in HTML, Bootstrap, CSS, and some PHP and JavaScript, but I can't seem to follow the difficult directions on how to get the Stripe Subscription Checkout working. Can someone please point me in the right direction or tell me how to fix my code. I'm on a tight deadline with the holidays.
First of all, there is a 404 error because the file was never there. In localhost or all servers, if you put a / before the file name it will automatically become after the host so /config.php will become http://localhost/config.php. To prevent this error, you should use ./
And the unexpected token < means the server is returning the 404 document.
In short, put a dot before the file name as I am assuming that this project is not in the root directory. (Means that the project is at http://localhost/projectName)
// Create a Checkout Session with the selected plan ID
var createCheckoutSession = function(priceId) {
return fetch("./create-checkout-session.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
priceId: priceId
})
}).then(function(result) {
return result.json();
});
};
and
/* Get your Stripe publishable key to initialize Stripe.js */
fetch("./config.php")
.then(function(result) {
return result.json();
})
.then(function(json) {
var publishableKey = json.publishableKey;
var basicPriceId = json.basicPrice;
var proPriceId = json.proPrice;
var stripe = Stripe(publishableKey);
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("basic-plan-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(basicPriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
// Setup event handler to create a Checkout Session when button is clicked
document
.getElementById("pro-plan-btn")
.addEventListener("click", function(evt) {
createCheckoutSession(proPriceId).then(function(data) {
// Call Stripe.js method to redirect to the new Checkout page
stripe
.redirectToCheckout({
sessionId: data.sessionId
})
.then(handleResult);
});
});
});

Private Chat Messaging using Node.js, Socket.io, Redis in PHP

I am working for a real time private messaging system into my php application. My codes are working for all users together. But I need private messaging system as one-to-one message.
After setup node and redis I can get the message data what I need : here is the code ::
Front-end ::
1. I use a form for - username , message and send button
and Notification JS:
$( document ).ready(function() {
var socket = io.connect('http://192.168.2.111:8890');
socket.on('notification', function (data) {
var message = JSON.parse(data);
$( "#notifications" ).prepend("<p> <strong> " + message.user_name + "</strong>: " + message.message + "</p>" );
});
});
Server Side js:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
server.listen(8890);
var users = {};
var sockets = {};
io.on('connection', function (socket) {
console.log(" New User Connected ");
// instance of Redis Client
var redisClient = redis.createClient();
redisClient.subscribe('notification');
socket.on('set nickname', function (name) {
socket.set('nickname', name, function () {
socket.emit('ready');
});
});
socket.on('msg', function () {
socket.get('nickname', function (err, name) {
console.log('Chat message by ', name);
});
});
redisClient.on("message", function(channel, message)
{
// to view into terminal for monitoring
console.log("Message from: " + message + ". In channel: " + channel + ". Socket ID "+ socket.id );
//send to socket
socket.emit(channel, message);
});
redisClient.on('update_chatter_count', function(data)
{
socket.emit('count_chatters', data);
});
//close redis
socket.on('disconnect', function()
{
redisClient.quit();
});
});
HTML::
<script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>
<form .....>
<input ....... >
</form>
<div id="notifications" ></div>
Over-all output:
John : Hello
Kate : Hi
Others: .....
Above codes are working nicely in my php application. Now I want to set-up private or one-to-one messaging system.
The way I need to add username or email or unique socketID for user. I do not have any more ideas for private messaging. I tried to figure on online but failed.
**How do I setup private message into my php application ? **
Basic initialization of variables:-
First, make a MAP of mapOfSocketIdToSocket and then send the userid of the specific user to whom you want to sent the message from the front-end. In the server, find the socket obeject mapped with the userid and emit your message in that socket. Here is a sample of the idea (not the full code)
var io = socketio.listen(server);
var connectedCount = 0;
var clients = [];
var socketList = [];
var socketInfo = {};
var mapOfSocketIdToSocket={};
socket.on('connectionInitiation', function (user) {
io.sockets.sockets['socketID'] = socket.id;
socketInfo = {};
socketInfo['userId']=user.userId;
socketInfo['connectTime'] = new Date();
socketInfo['socketId'] = socket.id;
socketList.push(socketInfo);
socket.nickname = user.name;
socket.userId= user.userId;
loggjs.debug("<"+ user.name + "> is just connected!!");
clients.push(user.userId);
mapOfSocketIdToSocket[socket.id]=socket;
}
socket.on('messageFromClient', function (cMessageObj, callback) {
for(var i=0; i<socketList.length;i++){
if(socketList[i]['userId']==cMessageObj['messageToUserID']){ // if user is online
mapOfSocketIdToSocket[socketList[i]['socketId']].emit('clientToClientMessage', {sMessageObj: cMessageObj});
loggjs.debug(cMessageObj);
}
}
})
Either you may want to go for private one-to-many chat room or you can go for one-to-one channel communication (if there are only two members communicating) http://williammora.com/nodejs-tutorial-building-chatroom-with/
I would suggest you to use socketIO namespaces, it allow you to send / emit event from / to specific communication "channels".
Here is the link to socketIO documentation regarding rooms & namespaces
http://socket.io/docs/rooms-and-namespaces/
Cheers
One solution could be sending messages to person with the particular socket id. As you are already using redis you can store the user's detail and socket id in redis when user joins and then to send messages to user by getting the socket id from the redis whenever you want to send him a message. Call events like
socket.emit('send private') from front end
and on backend handle the
socket.on('send private'){
// do redis stuff inside this }
Use Pusher. It offers channel usage to make private chats possible without any additional code

PHP + SockJS + Redis: Unicast

My application stack:
On my server runs a Redis server. The PHP backend communicates with Predis library with the Redis server. It will publish messages. These messages will be fetched by my Redis client (node.js) and pushed to the connected websocket clients (with SockJS).
My problem:
It runs well. At least for broadcast messages. Now I came to the point I need to send a unicast message and I'm stuck... How to connect the user on the backend side (sender of messages) with the connected client of the websocket?
Code snippets:
PHP
$redis = new Client();
$redis->publish('updates', Random::getUniqueString());
Redis client on node.js server
redis.subscribe('updates');
redis.on('message', function(channel, data) {
for (var id in sockets) {
if (sockets.hasOwnProperty(id)) {
sockets[id].write(data);
}
}
});
SockJS client
mySocketFactory.setHandler('message', function(event) {
console.log(event.data);
});
Like I said. Working well but the id used for the socket connection is not known by the PHP backend.
Edit: One idea I got in mind is to use cookies.
I found a way to solve my problem. When the socket connection is established I sent a request to my PHP backend and ask for the user id. This is stored on the node.js server. When messages are incoming there is a check if they are for specific user and handle them only for them.
So, what do I store exactly on my node server?
var sockets = {}; // {connection_id: socket_connection}
var connIdToUser = {}; // {connection_id: user_id}
var connIdsForUser = {}; // {user_id: [connection_id_1, connection_id_2 ,...]}
socketServer.on('connection', function(conn) {
sockets[conn.id] = conn;
var options = {
host: os.hostname(),
port: 80,
path: '/user/id',
method: 'GET'
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
var userId = JSON.parse(chunk).id;
connIdToUser[conn.id] = userId;
if (!connIdsForUser.hasOwnProperty(userId)) {
connIdsForUser[userId] = [];
}
connIdsForUser[userId].push(conn.id);
console.log('connection id ' + conn.id + ' related to user id ' + userId);
});
});
req.end();
conn.on('close', function() {
console.log('connection lost ' + conn.id);
// remove connection id from stack for user
var connections = connIdsForUser[connIdToUser[conn.id]];
var index = connections.indexOf(conn.id);
if (index > -1) {
connections.splice(index, 1);
}
// remove connection at all
delete sockets[conn.id];
// remove relation between connection id and user
delete connIdToUser[conn.id];
});
});
The reason for storing the relation between user id an connection id twice is the different use case I need either for sending a message or deleting the connection for the close event. Otherwise I would have to use a nested loop.
As you can see deleting a socket is fairly easy. Although deleting the connection from the connection stack of an user is a little bit complicated.
Let's continue with the sending of a message. Here I defined a structure of the message I get from the Redis server:
{
targets: [], // array of unit ids (can be empty)
data: <mixed> // the real data
}
Sending the data to the sockets looks like:
redis.on('message', function(channel, message) {
message = JSON.parse(message);
// unicast/multicast
if (message.targets.length > 0) {
message.targets.forEach(function(userId) {
if (connIdsForUser[userId] !== undefined) {
connIdsForUser[userId].forEach(function(connId) {
sockets[connId].write(message.data);
});
}
});
// broadcast
} else {
for (var id in sockets) {
if (sockets.hasOwnProperty(id)) {
sockets[id].write(message.data);
}
}
}
});
Since I store the connection stack per user it is quite easy to send the data to all sockets related to a specific user. So what I can do now is unicast (array with one user id), multicast (array with more than one user id) and broadcast (empty array).
It's working well for my use case.

How to integrate nodeJS + Socket.IO and PHP?

I have recently been looking around, to find a good way to communicate between nodeJS and PHP. Here is the idea : nodeJS is still quite new, and it can be kind of tricky to develop a full application only with it. Moreover, you may need it only for one module of your project, like realtime notifications, chat, ... And you want to manage all the other stuff with PHP, because it is probably more easy for you (and you can take advantage of the existing frameworks, like CodeIgniter or Symfony).
I would like to have an easy solution ; I don't want to use cURL, or a third server to communicate between Apache and Node servers. What I want is to be able to catch events from node in simple Javascript, client-side.
I didn't find any answers that where complete, most of the time client-side was running by the node server and so not applicable in my case. So I crawled all the possible topics, and finally find my answer ; I'll try to share this, and to have a point where it's all clear.
Hope this can help some people ! ;)
So, to begin with, I put my project on github, if you want access to the full code: https://github.com/jdutheil/nodePHP
It is a very simple example project: a web chat. You just have an author and message, and when you press send it is saved in a mysql database. The idea is to send real time updates, and have a real conversation. ;) We'll use nodeJS for that.
I won't talk about PHP code, it is really simple and not interesting here; what I want to show you is how to integrate your nodeJS code.
I use express and Socket.IO, so be sure to install those modules with npm. Then, we create a simple nodeJS server:
var socket = require( 'socket.io' );
var express = require( 'express' );
var http = require( 'http' );
var app = express();
var server = http.createServer( app );
var io = socket.listen( server );
io.sockets.on( 'connection', function( client ) {
console.log( "New client !" );
client.on( 'message', function( data ) {
console.log( 'Message received ' + data.name + ":" + data.message );
io.sockets.emit( 'message', { name: data.name, message: data.message } );
});
});
server.listen( 8080 );
We registered our events callback when a new user is connected ; every time we receive a message (represents a chat message), we broadcast it to every users connected. Now, the tricky part: client-side! That the part that took me most of the time, because I didn't know which script include to be able to run Socket.IO code without the nodeServer (because client page will be served by Apache).
But everything is already done; when you install Socket.IO module with npm, a script is available in /node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js; that the script we will include in our PHP page, in my case:
<script src="js/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js"></script>
<script src="js/nodeClient.js"></script>
And to finish, my nodeClient.js, where we simply connect to the node server and wait for event to update our page. ;)
var socket = io.connect( 'http://localhost:8080' );
$( "#messageForm" ).submit( function() {
var nameVal = $( "#nameInput" ).val();
var msg = $( "#messageInput" ).val();
socket.emit( 'message', { name: nameVal, message: msg } );
// Ajax call for saving datas
$.ajax({
url: "./ajax/insertNewMessage.php",
type: "POST",
data: { name: nameVal, message: msg },
success: function(data) {
}
});
return false;
});
socket.on( 'message', function( data ) {
var actualContent = $( "#messages" ).html();
var newMsgContent = '<li> <strong>' + data.name + '</strong> : ' + data.message + '</li>';
var content = newMsgContent + actualContent;
$( "#messages" ).html( content );
});
I'll try to update and improve my code as soon as possible, but I think it already open to all of cool things! I am really open for advice and reviews on this stuff, is it the good way to do it, .. ?
Hope this can help some people!
I have another solution that works quite well for me, but I would like someone to comment about how effective it is, as I have not (yet) had the opportunity/time to test it on the real server.
Here goes the node-js code. I put this code in a file called nodeserver.js:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var knall = new Object();
knall.totten = "4 tomtar";
knall.theArr = new Array();
knall.theArr.push("hoppla")
knall.theArr.push("hej")
var strKnall = JSON.stringify(knall);
res.end(strKnall);
}).listen(process.env.PORT);
And here is the simple piece of code in php, calling the node-js server with the help of file_get_contents():
$json = file_get_contents('http://localhost:3002/knall.json');
$obj = json_decode($json);
Works great, when I load the php-page, it in turn calls the nodeserver.js page, which jsonify the knall-object.
I have two localhost-installations running on iis on windows 10, one standard php-server, and the nodejs-server works with the neat iisnode package.
The 'real' server is run on ubuntu.
I think this is a neat and easy solution for communication between two servers, but maybe someone has any comments about it?
Try similar or you can check my blog for complete sample code on nodejs
On your page side:
Load Socket JS
https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js
Make object of the socket
var socket = io();
Use the emit function to send data to nodeserver.
socket.emit('new_notification', {
message: 'message',
title: 'title',
icon: 'icon',
});
So now your code will be look like
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
var socket = io();
$(document).ready(function($) {
$('.rules-table').on('click', '.runRule', function(event) {
event.preventDefault();
/* Act on the event */
var ruleID = $(this).parents('tr').attr('id');
// send notification before going to post
socket.emit('new_notification', {
message: 'Messge is ready to sent',
title: title,
icon: icon,
});
$.ajax({
url: '/ajax/run-rule.php',
type: 'POST',
dataType: 'json',
data: {
ruleID: ruleID
},
})
.done(function(data) {
console.log(data);
// send notification when post success
socket.emit('new_notification', {
message: 'Messge was sent',
title: title,
icon: icon,
});
})
.fail(function() {
console.log("error");
// send notification when post failed
socket.emit('new_notification', {
message: 'Messge was failed',
title: title,
icon: icon,
});
})
.always(function() {
console.log("complete");
});
});
});
Now on Node server side make handler for your request to get your request and send a message to all connected devices/browsers(server.js)
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res) {
res.sendfile('index.html');
});
io.on('connection', function (socket) {
socket.on( 'new_notification', function( data ) {
console.log(data.title,data.message);
// Now Emit this message to all connected devices
io.sockets.emit( 'show_notification', {
title: data.title,
message: data.message,
icon: data.icon,
});
});
});
http.listen(3000, function() {
console.log('listening on localhost:3000');
});
Now the client/browser/client side make a receiver to receive socket message from node server
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
var socket = io();
/**
* Set Default Socket For Show Notification
* #param {type} data
* #returns {undefined}
*/
socket.on('show_notification', function (data) {
showDesktopNotification(data.title, data.message, data.icon);
});
/**
* Set Notification Request
* #type type
*/
function setNotification() {
showDesktopNotification('Lokesh', 'Desktop Notification..!', '/index.jpeg');
sendNodeNotification('Lokesh', 'Browser Notification..!', '/index.jpeg');
}
/**
* Check Browser Notification Permission
* #type window.Notification|Window.Notification|window.webkitNotification|Window.webkitNotification|Window.mozNotification|window.mozNotification
*/
var Notification = window.Notification || window.mozNotification || window.webkitNotification;
Notification.requestPermission(function (permission) {
});
/**
* Request Browser Notification Permission
* #type Arguments
*/
function requestNotificationPermissions() {
if (Notification.permission !== 'denied') {
Notification.requestPermission(function (permission) {
});
}
}
/**
* Show Desktop Notification If Notification Allow
* #param {type} title
* #param {type} message
* #param {type} icon
* #returns {undefined}
*/
function showDesktopNotification(message, body, icon, sound, timeout) {
if (!timeout) {
timeout = 4000;
}
requestNotificationPermissions();
var instance = new Notification(
message, {
body: body,
icon: icon,
sound: sound
}
);
instance.onclick = function () {
// Something to do
};
instance.onerror = function () {
// Something to do
};
instance.onshow = function () {
// Something to do
};
instance.onclose = function () {
// Something to do
};
if (sound)
{
instance.sound;
}
setTimeout(instance.close.bind(instance), timeout);
return false;
}

Categories