PHP Websocket possibly not going through Cloudflare at all? - php

I'm currently using Ratchet PHP Websockets example code (http://socketo.me/docs/hello-world) and when I try to run the Websocket it doesn't output anything but does show that it's "live".
On my website I'm using the very same JS code as the example except using wss:// as my website is going through Cloudflare's SSL. Now my question is, when I try to connect to the websocket, in my Chrome developer tools it just continuously shows pending and will terminate if I turn the websocket off.
I cannot find a way to debug what is going on with it, I'm using the ports that Cloudflare allows me to use (which is :8443) and I am on a plan where Websockets are supported by Cloudflare. But I cannot seem to find any answers about using Websockets through cloudflare and when I turn on error_reporting it doesn't seem to output anything either.
Is it something with Cloudflare? When I type php runwebsocket.php is it supposed to output something besides nothing?
When I used this script for the Websockets (https://github.com/ghedipunk/PHP-Websockets) it would output if a client has connected to the socket but would still give me the same issue where it's not actually fully connecting to it.
EDIT: When I go to the Websocket Echo testing site when I try to connect to my socket it just doesn't output anything either.
**EDIT #2:
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
require('vendor/autoload.php'); // composer require cboden/ratchet
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use AppSocket\Notifications;
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Notifications()
)
),
8443
);
$server->run();
Code for AppSocket\Notifications
<?php
namespace AppSocket;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Notifications implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
echo "Yay";
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}

Related

Send message from PHP script to a PHP ratchet websocket server without ZMQ or any PECL packages

CONTEXT
I am using RatchetPHP to let my HTML clients to be in sync with themselves.
websocket-server.php
I run this file using php websocket-server.php, which loops indefinitively to handle websocket connections and messages.
<?php
require __DIR__ . "/../vendor/autoload.php";
use Me\Server;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Server()
)
),
8000
);
$server->run();
client.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<script>
var conn = new WebSocket("ws://127.0.0.1:8000");
conn.onopen = function(e) {
console.log("Connection established!");
setTimeout(function() {
conn.send("coucou");
}, 5000);
};
conn.onmessage = function(e) {
console.log(e.data);
};
</script>
</body>
</html>
Me\Server.php
This is the Server that handles events (messages, connections).
namespace Me;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use SplObjectStorage;
class Server implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
, $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
ATTEMPT
I also need my back-end to send messages to the socket server that will himself send a message to all the connected clients. This is a Laravel back-end that for example will send a message to clients to inform that a new user record is available and they should reload their web page. Here is my attempt:
send.php
$address="127.0.0.1";
$port="8000";
$msg="new user available";
$sock=socket_create(AF_INET,SOCK_STREAM,0) or die("Cannot create a socket");
socket_connect($sock,$address,$port) or die("Could not connect to the socket");
$result = socket_write($sock,$msg);
socket_close($sock);
What I noticed is that Ratchet is parsing HTTP messages, so if I understand right I need to send an HTTP message instead of a plain messages (I confirmed it, because if I print the raw message before it being parsed in the file vendor/cboden/ratchet/src/Ratchet/Http/HttpServer.php at the begining of the method onMessage, I can see my message, but then the check if (true !== $from->httpHeadersReceived) { does not pass because I am sending a raw text).
QUESTION
How can I send an HTTP message to a web socket server without any dependencies like ReactZMQ and some PECL packages?

I'm unable to cross communicate with ReactPHP's Pawl and Ratchet

I'm currently attempting to connect to two different socket servers. One of them is essentially an IRC connection, the other is an interface server that I've made myself. These two loops need to be able to communicate with each other, but I'm having difficulty actually sending a message from one connection to another.
Here's what I've been trying as a simplified way of injecting the message, the comments are not very confident because I'm honestly not sure where I'm going wrong:
<?php
require __DIR__ . '/vendor/autoload.php';
// EventLoop the way I understand it is designed to split up your loops and
// run them one after another so you can kind of multithread, even though
// it's just one step of the loop at a time.
$loop = \React\EventLoop\Factory::create();
// Verbose defintion of connectors mainly trying to just gain extra control
// and so I could see how each thing was defined.
$reactConnector = new \React\Socket\Connector($loop, [
'dns' => '8.8.8.8',
'timeout' => 10
]);
$connector = new \Ratchet\Client\Connector($loop, $reactConnector);
// Connect as a client to the development Socket server. This is all just
// from the Pawl github essentially.
//
// The connection is successful every time.
$ws = $connector('ws://0.0.0.0:5069', [], ['Origin' => 'http://localhost']);
->then(function(Ratchet\Client\WebSocket $conn) {
// Simple echo on message received for the test.
$conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
echo "Received: {$msg}\n";
});
$conn->on('close', function($code = null, $reason = null) {
echo "Connection closed ({$code} - {$reason})\n";
});
$conn->send('Hello World!');
}, function(\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
});
// Instead of including a second socket connector I decided to use a simple
// timer and try to get it to use the client connection above to send
// messages to the socket server.
//
// The problem is here, I can't get the socket server to send a message
// from outside of the ->then();
$loop->addPeriodicTimer(1, function () use ($ws) {
$ws->then(function (Ratchet\Client\WebSocket $conn) {
$conn->send('Figured out?');
});
});
$loop->run();
I'd really like to be able to send messages from one connection the the other through some sort of $ws->send('message');, but I can't for the life of me figure out how.
Ahhh Finally a question I can answer!! I spent most of yesterday working through my own Ratchet/Pawl client that had to have addPeriodicTimer loops to send content at periodic times. It took some poking around but I made it work by placing the $loop->addPeriodicTimer() call INSIDE of the connector block, after the ->then(function(Ratchet\Client\WebSocket $conn) part and before the $conn->on('message'...) calls. Also for the $loop->addPeriodicTimer calls make sure to add the use clause passing in the connection ... and make sure to add the use clause passing in the $loop to the connector.
<?php
require __DIR__ . '/vendor/autoload.php';
// EventLoop the way I understand it is designed to split up your loops and
// run them one after another so you can kind of multithread, even though
// it's just one step of the loop at a time.
$loop = \React\EventLoop\Factory::create();
// Verbose defintion of connectors mainly trying to just gain extra control
// and so I could see how each thing was defined.
$reactConnector = new \React\Socket\Connector($loop, [
'dns' => '8.8.8.8',
'timeout' => 10
]);
$connector = new \Ratchet\Client\Connector($loop, $reactConnector);
// Connect as a client to the development Socket server. This is all just
// from the Pawl github essentially.
//
// The connection is successful every time.
$ws = $connector('ws://0.0.0.0:5069', [], ['Origin' => 'http://localhost']);
->then(function(Ratchet\Client\WebSocket $conn) use ( $loop ) {
$loop->addPeriodicTimer(1, function () use ( $conn ) {
$conn->send('Figured out?');
});
// Simple echo on message received for the test.
$conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
echo "Received: {$msg}\n";
});
$conn->on('close', function($code = null, $reason = null) {
echo "Connection closed ({$code} - {$reason})\n";
});
$conn->send('Hello World!');
}, function(\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
});
$loop->run();

Sending a message to a Ratchet PHP Websocket Server's client

I am using this server script to create a Websocket server (server.php). This works fine.
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\WebSocket\WsServerInterface;
require 'vendor/autoload.php';
require_once 'db.php';
class MyClass implements MessageComponentInterface, WsServerInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
$name = str_replace('/', '', $conn->httpRequest->getUri()->getPath());
$resourceId = $conn->resourceId;
$stmt = $db->prepare("INSERT INTO clients (id, resourceId, name) VALUES (null, :resourceId, :name)");
$stmt->bindParam(':resourceId', $resourceId, PDO::PARAM_STR);
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
$stmt->execute();
ConnectDB::closeConnection($db);
echo "Connected (" . $resourceId . ")\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$name = str_replace('/', '', $conn->httpRequest->getUri()->getPath());
$request = json_decode($msg);
if (json_last_error() === JSON_ERROR_NONE) {
require_once 'process.php';
$response = processRequest($msg);
if ($response !== false) {
$from->send($response);
}
} else {
$from->send('JSON error');
$ActionType = 'Connect';
}
echo "Incoming message - " $name "\n";
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Closed\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
$conn->close();
}
}
$server = IoServer::factory(
new HttpServer(
new WsServer(
new MyClass()
)
),
8080
);
$server->run();
I am saving the ID of $resourceId = $conn->resourceId; to a database.
What I would like to do is have another php script, currently test.php that could send messages to the clients via Ratchet.
Here is test.php
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\WebSocket\WsServerInterface;
require 'vendor/autoload.php';
require_once 'db.php';
$to = 119; // hard-coded id, not using database yet
$msg = json_encode(array("test" => "test"));
class Sender implements MessageComponentInterface, ConnectionInterface {
public function send(ConnectionInterface $to, $msg) {
$client = $this->clients[$to];
$client->send($msg);
}
}
Sender::send($to, $msg);
Error:
Fatal error: Declaration of Sender::send() must be compatible with Ratchet\ConnectionInterface::send($data) in test.php on line 20
This does not work and I do not know if this is the correct approach. I don't want to reply to an incoming message (that currently works), rather ultimately send a message from a form at test.php.
The Ratchet examples (Hello world) basically use the server to relay the messages between clients. In my case, I only want the server to communicate back and forth to individual clients. Clients never talk to each other. Also, the form at test.php does not create a client, nor does it expect an answer.
Can someone steer me in the right direction to send messages directly to clients?

RatchetPHP unable to send messages to all clients in loop

I'm using Ratchet PHP to send messages to clients, and I'm using
$server->loop->addPeriodicTimer(1, function () use ($row, $server) {...
To send a message every second. I can echo the message and the MySQL query works, but I am unable to actually access the clients object in $server, I can get to $server->app, but then when I do ->clients after that, it tells me that $clients doesn't exist.
To clarify, this isn't a problem when I don't use new HttpServer(...) but, without it, the browser console says the websocket handshake isn't valid, so that isn't a good workaround.
I've used print_r($server) and have confirmed that the clients object is inside a _httpServer:protected item. If I can access this, I'd be able to send messages, I think.
The code for the actual server video-server.php:
<?php
include "../../include/db.info.php";
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\Factory;
use MyApp\Chat;
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
), 888
);
$pdo = new PDO("mysql:host=localhost;port=3306;dbname=erewhon", "root", "");
$getUsername = $pdo->prepare("SELECT * FROM messages WHERE id=201");
$getUsername->execute();
$row = $getUsername->fetch(PDO::FETCH_ASSOC);
$server->loop->addPeriodicTimer(1, function () use ($row, $server) {
/*foreach ($server->app->component->clients as $client) {
$client->send("hello client");
}*/
print_r($server->app);
});
$server->run();
?>
The code for the classes file, chat.php:
<?php
namespace MyApp;
header("Content-Type: application/json; charset=UTF-8");
//include "../../db.info.php";
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
public $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
echo "Congratulations! the server is now running\n";
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
//dont need this
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
?>
It seems that you can't get that data the way you want.
The HttpServer define a protected variable.
protected $_httpServer; //<--- protected, you can't read from outside.
public function __construct(HttpServerInterface $component) {
$this->_httpServer = $component;
$this->_reqParser = new HttpRequestParser;
}
But, you can pass a instance of Chat and keep track of it. It will point to the same memory address.
Make a try:
$chat = new Chat(); //<--- ADD THIS LINE
$server = IoServer::factory(
new HttpServer(
new WsServer(
$chat //<----- USE HERE
)
), 888
);
....
$server->loop->addPeriodicTimer(1, function () use ($row, $server, $chat) {
/*foreach ($server->app->component->clients as $client) {
$client->send("hello client");
}*/
print_r($server->app);
print_r($chat->clients); // <---- PRINT HERE TO GET THE INFO
});
I've got my original answer below just in case, but I'd like to highlight that the accepted answer is the correct method, just don't forget to pass it to use
I know I probably shouldn't have done this to work around my problem, but it resolved it, so it is sufficient:
I went to vendor\cboden\ratchet\src\Ratchet\Http and edited HttpServer.php, specifically the variable protected $_httpServer, and changed it to public $_httpServer, which I probably shouldn't have, but that resolved my problem.
I could access the clients item by doing $server->app->_httpServer->component->clients.
Thanks to Felippe Duarte for highlighting this attribute, I didn't think of that.

How to get events in PAMI

I successfully insttalled PAMI in my server where asterisk is setup. And i wrote a new php file which
class A implements IEventListener
{
public function handle(EventMessage $event)
{
print_r("Inside");
}
}
$pamiClient = new PamiClient($pamiClientOptions);
$pamiClient->registerEventListener(new A());
$pamiClient->open();
$running = true;
while($running) {
$pamiClient->process();
usleep(1000);
}
$pamiClient->close();
But when i generate a call it doesnot catch the event. How can i know it is connected with asterisk, and how can i test this? Iam justng running this php file .
How i can know it connected to asterisk:
tcpdump -vv dst port 5038
how can i test this
Use debugger.

Categories