通常のphpやhtmlを使ったwebアプリケーションではリアルタイムに双方向通信をするのが難しい。
WebSocketという規格を使えばこの課題を解決でき、PHP上で動くRatchetというライブラリがあったので備忘録を残す
Composerをインストールする
composerはphpの外部ライブラリを管理するアプリケーション。
これによりRatchetの動作に必要なReact, Guzzle, HttpFoundationを解決してくれる。
任意のフォルダーで以下を実行
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
phpの実行ファイルであるcomposer.pharが生成されていればOK
Ratchetをインストールする
前項を実行したフォルダーで以下を実行。ファイル群が生成される。
php composer.phar require cboden/ratchet
以降Ratchetを使いたいファイルにvendor/autoload.phpを読み込むように設定すればよい。
require 'vendor/autoload.php';
フォルダを分けたい場合は以下のマジカル定数などを利用し適宜変更
require __DIR__ . '/vendor/autoload.php';
MyChatクラスを作成する
同フォルダーに送信、受信、切断、接続があったときの動作を制定するクラスを作成する。ここでのファイル名はMyChat.phpとする
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class MyChat 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();
}
}
webサーバーロジックを作成する
これを常時起動させることでクライアントがメッセージをやり取りできるようになる。ファイル名は何でも良いがwebserver.phpとする。
<?php
// Your shell script
use MyApp\MyChat;
use Ratchet\WebSocket\WsServer;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
require 'vendor/autoload.php';
$ws = new WsServer(new MyChat);
// Make sure you're running this as root
$server = IoServer::factory(new HttpServer($ws),8080);
$server->run();
依存関係を設定
同フォルダのcomposer.jsonに追記する。
MyChat.phpの名前空間MyAppがカレントフォルダにあることを設定している。適宜変更
{
"autoload": {
"psr-4": {
"MyApp\\": "./"
}
},
"require": {
"cboden/ratchet": "^0.4"
}
}
書き込みが終了したら忘れずに
php composer.phar update
ターミナルから以下を実行し、何も応答がなければ成功。
php webserver.php
フロントエンドの作成
JavaScriptでフロントエンド側の処理を記述する。localhostにMyChat.htmlなどと保存する。
<script>
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function (e) {
console.log("connection for comment established!");
};
conn.onmessage = function (e) {
console.log(e.data);
};
function send(text) {
conn.send(text);
}
</script>
動作確認
Chromeを開き右クリック→「検証」
URLバーに該当するアドレス(localhost/MyChat.htmlなど)を挿入する
コンソールからsend(“text”);などとしてやると送信され、phpのwebserverが起動しているターミナルから確認できる。
webserver.phpは常時起動していないと行けないので、nohupを使うのが良いと思われ
nohup php webserver.php & >> /dev/null/