Reputation: 4647
Is it possible to use Sockets.io on the client side and communicate with a PHP based application on the server? Does PHP even support such a 'long-lived connection' way of writing code?
All the sample code I find for socket.io seems to be for node.js on the server side, so no help there.
Upvotes: 156
Views: 256868
Reputation: 1
as far as I know you can't use socket.io with PHP. Here is the solution to your problem: Use websockets through a library called RatChet.
Here is the sample code of chat system I built using websocket:
You first need a server.php file:
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use App\MainHandler;
include_once("database.php");
// Create WebSocket server
$server = IoServer::factory(
new HttpServer(
new WsServer(
new MainHandler($conn)
)
),
8080
);
echo "WebSocket server started on ws://localhost:8080\n";
$server->run();
Then you need to create for clients to build connection with your server. In my case, it's webcoket.js:
const socket = new WebSocket(`ws://127.0.0.1:8080`);
let sender_id;
if(window.location.search !== ""){
sender_id = window.location.search.split("sender_id")[1].substring(1);
}
// Connection opened
socket.onopen = () => {
console.log("Connection established");
socket.send(JSON.stringify({
type : "establish_notifications",
sender_id : sender_id,
}));
console.log('WebSocket connection established for sender_id:', sender_id);
};
// Handle errors
socket.onerror = (error) => {
console.log('WebSocket error:', error);
};
// Handle connection close
socket.onclose = () => {
console.log('Connection closed');
};
export default socket;
I have built two features, live chats and live notification for those chats, and in Wsserver, you cann add only handler:
const socket = new WebSocket(`ws://127.0.0.1:8080`);
let sender_id;
if(window.location.search !== ""){
sender_id = window.location.search.split("sender_id")[1].substring(1);
}
// Connection opened
socket.onopen = () => {
console.log("Connection established");
socket.send(JSON.stringify({
type : "establish_notifications",
sender_id : sender_id,
}));
console.log('WebSocket connection established for sender_id:', sender_id);
};
// Handle errors
socket.onerror = (error) => {
console.log('WebSocket error:', error);
};
// Handle connection close
socket.onclose = () => {
console.log('Connection closed');
};
export default socket;
Here is my chat.php file:
<?php
namespace Library;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
protected $clients;
protected $token;
protected $dbconn;
protected $chatTokens; // Store tokens and associated connections
public function __construct($dbconnection) {
$this->clients = new \SplObjectStorage;
$this->dbconn = $dbconnection;
$this->chatTokens = []; // Format: ['token' => [ConnectionInterface]]
}
public function onOpen(ConnectionInterface $wsconn) {
$this->clients->attach($wsconn);
echo "New connection! ({$wsconn->resourceId})\n";
}
public function onMessage(ConnectionInterface $wsconn, $msg) {
$data = json_decode($msg, true);
$sender_id = $data['sender_id'];
$receiver_id = $data['receiver_id'];
//GENERATE TOKEN OR GET TOKEN FROM DB
if($data['type'] === 'token'){
$select = "SELECT token FROM messages
WHERE (sender_id = '$sender_id' AND receiver_id = '$receiver_id')
OR (receiver_id = '$sender_id' AND sender_id = '$receiver_id')
LIMIT 1";
$result = mysqli_query($this->dbconn, $select);
if ($row = mysqli_fetch_assoc($result)) {
$this->token = $row['token'];
} else {
$this->token = $this->createChatToken();
// $this->token = $this->createChatToken();
// if(isset($this->chatTokens[$this->token])){
// $this->chatTokens[$this->token] = [];
// }
}
// if(!isset($this->chatTokens[$this->token])){
// $this->chatTokens[$this->token] = [];
// }
if (!isset($this->chatTokens[$this->token])) {
$this->chatTokens[$this->token] = [];
}
// Check if the connection already exists
if (!in_array($wsconn, $this->chatTokens[$this->token], true)) {
// Add the connection only if it's not already present
$this->chatTokens[$this->token][] = $wsconn;
}
// $this->chatTokens[$this->token][] = $wsconn;
// echo $this->token;
}
if($data['type'] === 'message' || !isset($data['type'])){
$message_text = $data['message_text'];
$insert = "INSERT INTO messages (sender_id, receiver_id, message_text, token) VALUES ('$sender_id', '$receiver_id', '$message_text', '$this->token')";
$mysqli_insert_query = mysqli_query($this->dbconn, $insert);
if($mysqli_insert_query){
echo "Inserted data into database";
}else{
echo "Could not insert into database";
}
// Route the message only to connections associated with the token
foreach ($this->chatTokens[$this->token] as $client) {
$client->send(json_encode([
'token' => $this->token,
'type' => 'message',
'sender_id' => $sender_id,
'receiver_id' => $receiver_id,
'message_text' => $message_text
]));
// echo "Data {$message_text} sent to {$receiver_id}";
}
}
}
public function onClose(ConnectionInterface $wsconn) {
// Detach connection
$this->clients->detach($wsconn);
foreach($this->chatTokens as $token => &$connections){
foreach($connections as $index => $connection){
if($connection === $wsconn){
unset($connections[$index]);
}
}
}
echo "Connection {$wsconn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $wsconn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$wsconn->close();
}
// Generate a unique token for a new chat session
public function createChatToken() {
$tok = bin2hex(random_bytes(16)); // Generate a secure random token
return $tok;
}
}
?>
Here is my notification.php file:
<?php
namespace Library;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
include_once("send_email.php");
class Notification implements MessageComponentInterface{
protected $clients;
protected $NotificationToken;
protected $dbconn;
public function __construct($dbconnection){
$this->dbconn = $dbconnection;
$this->clients = [];
}
public function onOpen(ConnectionInterface $wsconn){
//EXTRACTED THE RECEIVER ID FROM URL
// $query = $wsconn->httpRequest->getUri()->getQuery();
// parse_str($query, $queryParams);
// $sender_id = $queryParams['sender_id']??null;
// $receiver_id = $queryParams['receiver_id']??null;
//SET THE CONNECTION IN CLIENTS
// if($sender_id && $receiver_id){
// $key = $sender_id.'_'.$receiver_id;
// $this->clients[$key] = [];
// }
// $this->clients[$key][] = $wsconn;
echo "Notification opened";
}
public function onMessage(ConnectionInterface $wsconn, $msg){
$data = json_decode($msg, true);
echo "Message data received! {$data['type']}";
if($data['type'] === 'establish_notifications'){
$sender_id = $data['sender_id'];
// if(!isset($this->clients[$sender_id])){
// $this->clients[$sender_id] = null;
// }
$this->clients[$sender_id] = $wsconn;
$wsconn->send(json_encode([
'type' => 'notification_established',
'message_text' => 'Notifications established for the sender'
]));
echo "Sender notification ID created!";
}
// $receiver_id = $data['receiver_id'];
// $sender_id = $data['sender_id'];
// $key = $receiver_id.'_'.$sender_id;
// $sender_receiver_key = $sender_id.'_'.$receiver_id;
// if(isset($this->clients[$sender_receiver_key])){
// $this->clients[$sender_receiver_key] = [];
// }
// $this->clients[$sender_receiver_key][] = $wsconn;
// $receiver_sender_key = $receiver_id.'_'.$sender_id;
if($data['type'] === 'notification'){
$receiver_id = $data['receiver_id'];
$sender_id = $data['sender_id'];
$message_text = $data['message_text'];
// if(isset($this->clients[$key])){
// if(isset($this->clients[$receiver_sender_key])){
// // foreach($this->clients[$key] as $client){
// foreach($this->clients[$receiver_sender_key] as $client){
// $client->send(json_encode([
// 'type' => 'notification',
// 'sender_id' => $sender_id,
// 'receiver_id' => $receiver_id,
// 'message_text' => $message_text
// ]));
// // echo "Notification: {$message_text}";
// }
// }
if(isset($this->clients[$receiver_id])){
// foreach($this->clients[$key] as $client){
// foreach($this->clients as $key => $client){
// if($key === $receiver_id){
$client =$this->clients[$receiver_id];
$client->send(json_encode([
'type' => 'notification',
'sender_id' => $sender_id,
'receiver_id' => $receiver_id,
'message_text' => $message_text
]));
//SELECT RECEIVER EMAIL FROM DB
$select = "SELECT email, full_name FROM users WHERE id = '$receiver_id'";
$mysqli_select_query = mysqli_query($this->dbconn, $select);
while($rows = mysqli_fetch_assoc($mysqli_select_query)){
$receiver_email = $rows['email'];
$receiver_full_name = $rows['full_name'];
}
$send_email = send_email("{$receiver_email}", "{$receiver_full_name}", "New Message Received", $message_text);
if($send_email){
echo "Email sent!";
}else{
echo "Could not send email!";
}
// }
// // echo "Notification: {$message_text}";
// }
}else{
echo "Receiver ID not found!";
}
}
}
public function onClose(ConnectionInterface $wsconn){
foreach ($this->clients as $id => $client) {
if ($client === $wsconn) {
// $this->clients[$id] = null;
}
}
}
public function onError(ConnectionInterface $wsconn, \Exception $e){
echo "onError: {$e->getMessage()}";
}
}
?>
Upvotes: 0
Reputation: 296
If you really want to use PHP as your backend for socket.io, here are what I found. This is two socket.io php server side alternatives.
Example code for the first repository like this:
use PHPSocketIO\SocketIO;
// listen port 2021 for socket.io client
$io = new SocketIO(2021);
$io->on('connection', function($socket)use($io){
$socket->on('chat message', function($msg)use($io){
$io->emit('chat message', $msg);
});
});
Upvotes: 26
Reputation: 8144
I was looking for a really simple way to get PHP to send a socket.io message to clients.
This doesn't require any additional PHP libraries - it just uses sockets.
Instead of trying to connect to the websocket interface like so many other solutions, just connect to the node.js server and use .on('data')
to receive the message.
Then, socket.io
can forward it along to clients.
Detect a connection from your PHP server in Node.js like this:
//You might have something like this - just included to show object setup
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
server.on("connection", function(s) {
//If connection is from our server (localhost)
if(s.remoteAddress == "::ffff:127.0.0.1") {
s.on('data', function(buf) {
var js = JSON.parse(buf);
io.emit(js.msg,js.data); //Send the msg to socket.io clients
});
}
});
Here's the incredibly simple php code - I wrapped it in a function - you may come up with something better.
Note that 8080
is the port to my Node.js server - you may want to change.
function sio_message($message, $data) {
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($socket, '127.0.0.1', 8080);
if(!$result) {
die('cannot connect '.socket_strerror(socket_last_error()).PHP_EOL);
}
$bytes = socket_write($socket, json_encode(Array("msg" => $message, "data" => $data)));
socket_close($socket);
}
You can use it like this:
sio_message("chat message","Hello from PHP!");
You can also send arrays which are converted to json and passed along to clients.
sio_message("DataUpdate",Array("Data1" => "something", "Data2" => "something else"));
This is a useful way to "trust" that your clients are getting legitimate messages from the server.
You can also have PHP pass along database updates without having hundreds of clients query the database.
Upvotes: 1
Reputation: 366
I know the struggle man! But I recently had it pretty much working with Workerman. If you have not stumbled upon this php framework then you better check this out!
Well, Workerman is an asynchronous event driven PHP framework for easily building fast, scalable network applications. (I just copied and pasted that from their website hahahah http://www.workerman.net/en/)
The easy way to explain this is that when it comes web socket programming all you really need to have is to have 2 files in your server or local server (wherever you are working at).
server.php (source code which will respond to all the client's request)
client.php/client.html (source code which will do the requesting stuffs)
So basically, you right the code first on you server.php and start the server. Normally, as I am using windows which adds more of the struggle, I run the server through this command --> php server.php start
Well if you are using xampp. Here's one way to do it. Go to wherever you want to put your files. In our case, we're going to the put the files in
C:/xampp/htdocs/websocket/server.php
C:/xampp/htdocs/websocket/client.php or client.html
Assuming that you already have those files in your local server. Open your Git Bash or Command Line or Terminal or whichever you are using and download the php libraries here.
https://github.com/walkor/Workerman
https://github.com/walkor/phpsocket.io
I usually download it via composer and just autoload those files in my php scripts.
And also check this one. This is really important! You need this javascript libary in order for you client.php or client.html to communicate with the server.php when you run it.
https://github.com/walkor/phpsocket.io/tree/master/examples/chat/public/socket.io-client
I just copy and pasted that socket.io-client folder on the same level as my server.php and my client.php
Here is the server.php sourcecode
<?php
require __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use PHPSocketIO\SocketIO;
// listen port 2021 for socket.io client
$io = new SocketIO(2021);
$io->on('connection', function($socket)use($io){
$socket->on('send message', function($msg)use($io){
$io->emit('new message', $msg);
});
});
Worker::runAll();
And here is the client.php or client.html sourcecode
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="chat-messages" style="overflow-y: scroll; height: 100px; "></div>
<input type="text" class="message">
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="socket.io-client/socket.io.js"></script>
<script>
var socket = io.connect("ws://127.0.0.1:2021");
$('.message').on('change', function(){
socket.emit('send message', $(this).val());
$(this).val('');
});
socket.on('new message', function(data){
$('#chat-messages').append('<p>' + data +'</p>');
});
</script>
</html>
Once again, open your command line or git bash or terminal where you put your server.php file. So in our case, that is C:/xampp/htdocs/websocket/ and typed in php server.php start and press enter.
Then go to you browser and type http://localhost/websocket/client.php to visit your site. Then just type anything to that textbox and you will see a basic php websocket on the go!
You just need to remember. In web socket programming, it just needs a server and a client. Run the server code first and the open the client code. And there you have it! Hope this helps!
Upvotes: 15
Reputation: 4379
UPDATE: Aug 2014 The current socket.io v1.0 site has a PHP example:- https://github.com/rase-/socket.io-php-emitter
Upvotes: 23
Reputation: 1274
Look in this libraryes for php http://phptrends.com/category/70. Or use native from php http://www.php.net/manual/en/book.sockets.php .
Upvotes: 0
Reputation: 7026
If you want to use socket.io together with php this may be your answer!
project website:
they are also on github:
https://github.com/wisembly/elephant.io
Elephant.io provides a socket.io client fully written in PHP that should be usable everywhere in your project.
It is a light and easy to use library that aims to bring some real-time functionality to a PHP application through socket.io and websockets for actions that could not be done in full javascript.
example from the project website (communicate with websocket server through php)
php server
use ElephantIO\Client as Elephant;
$elephant = new Elephant('http://localhost:8000', 'socket.io', 1, false, true, true);
$elephant->init();
$elephant->send(
ElephantIOClient::TYPE_EVENT,
null,
null,
json_encode(array('name' => 'foo', 'args' => 'bar'))
);
$elephant->close();
echo 'tryin to send `bar` to the event `foo`';
socket io server
var io = require('socket.io').listen(8000);
io.sockets.on('connection', function (socket) {
console.log('user connected!');
socket.on('foo', function (data) {
console.log('here we are in action event and data is: ' + data);
});
});
Upvotes: 79
Reputation: 4546
How about this ? PHPSocketio ?? It is a socket.io php server side alternative. The event loop is based on pecl event extension. Though haven't tried it myself till now.
Upvotes: 4
Reputation: 283313
I haven't tried it yet, but you should be able to do this with ReactPHP and this socket component. Looks just like Node, but in PHP.
Upvotes: 2
Reputation: 111
For 'long-lived connection' you mentioned, you can use Ratchet for PHP. It's a library built based on Stream Socket functions that PHP has supported since PHP 5.
For client side, you need to use WebSocket that HTML5 supported instead of Socket.io (since you know, socket.io only works with node.js).
In case you still want to use Socket.io, you can try this way: - find & get socket.io.js for client to use - work with Ratchet to simulate the way socket.io does on server
Hope this helps!
Upvotes: 7
Reputation: 2083
If you really want to use PHP as your backend for WebSockets, these links can get you on your way:
https://github.com/lemmingzshadow/php-websocket
Upvotes: 4
Reputation: 60835
It may be a little late for this question to be answered, but here is what I found.
I don't want to debate on the fact that nodes does that better than php or not, this is not the point.
The solution is : I haven't found any implementation of socket.io for PHP.
But there are some ways to implement WebSockets. There is this jQuery plugin allowing you to use Websockets while gracefully degrading for non-supporting browsers. On the PHP side, there is this class which seems to be the most widely used for PHP WS servers.
Upvotes: 108
Reputation: 3269
Erm, why would you want to? Leave PHP on the backend and NodeJS/Sockets to do its non-blocking thing.
Here is something to get you started: http://groups.google.com/group/socket_io/browse_thread/thread/74a76896d2b72ccc
Personally I have express running with an endpoint that is listening expressly for interaction from PHP.
For example, if I have sent a user an email, I want socket.io to display a real-time notification to the user.
Want interaction from socket.io to php, well you can just do something like this:
var http = require('http'),
host = WWW_HOST,
clen = 'userid=' + userid,
site = http.createClient(80, host),
request = site.request("POST", "/modules/nodeim/includes/signonuser.inc.php",
{'host':host,'Content-Length':clen.length,'Content-Type':'application/x-www-form-urlencoded'});
request.write('userid=' + userid);
request.end();
Seriously, PHP is great for doing server side stuff and let it be with the connections it has no place in this domain now. Why do anything long-polling when you have websockets or flashsockets.
Upvotes: 6