11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【PHP】爆速でPubSubアプリが作れるThruway

Last updated at Posted at 2018-09-08

PHPでチャットしたい

現在1php websocketとかでググるとRatchetというライブラリが真っ先にヒットします。私も最初はこれを弄っていました。

ですがRatchetはWAMPv2に対応していないという致命的な欠点を抱えています。

そのため何気なくnpm install autobahnとかして最新のautobahn.js(WAMPv2対応)を突っ込んだりするとプロトコル違いが原因でhandshakeに失敗します。公式のtutorialで使ってるのに!

困って他をあたったところ、Thruwayというライブラリを見つけました。これが触ってみたらとてもいい感じでした。

しかし日本語の情報がわずかしかないので、ここではチャットアプリの実装を通じてThruwayの使い方を広めようと思います。

Thruwayだけでclientサイドまでphpオンリーで実装できますが、今回はclientサイドはautobahnで行くことにします。

前提条件

下記ツールを用いますので、持ってない人は/(apt-get|yum|dnf|インストール)/してください。

  • 必須

    • composer
  • autobahn使わないならいらない

    • node.js
    • bower

インストール

composer require voryx/thruway
composer require thruway/pawl-transport

以上。

autobahn.jsなどを、クライアントサイドに使う場合はcomposer require voryx/thruwayのみでOKです。

今回はphpだけで動作確認までしたいのでthruway/pawl-transportまで入れましょう。

動作確認

php vendor/voryx/thruway/Examples/SimpleWsRouter.php

こんな感じでRouterが走り出します。

2018-09-08T07:15:54.0880690 debug      [Thruway\Peer\Router 32351] New router created
2018-09-08T07:15:54.0896410 info       [Thruway\Peer\Router 32351] Starting router
2018-09-08T07:15:54.0903750 info       [Thruway\Transport\RatchetTransportProvider 32351] Websocket listening on 127.0.0.1:9090
2018-09-08T07:15:54.0906830 info       [Thruway\Peer\Router 32351] Starting loop

Starting loopしたらもう一個terminalを立ち上げてclient側を動かします。

php vendor/voryx/thruway/Examples/SimpleClient.php

最初に動かしたRouterがこんな感じの出力を吐けばちゃんと動いています。最後の方のonMessageが大事。

2018-09-08T07:20:34.2795810 debug      [Thruway\Transport\RatchetTransportProvider 1812] RatchetTransportProvider::onOpen
2018-09-08T07:20:34.2858580 debug      [Thruway\Transport\RatchetTransportProvider 1812] onMessage: ([1,"realm1",{"roles":{"publisher":{"features":{"subscriber_blackwhite_listing":true,"publisher_exclusion":true}},"subscriber":{"features":{}},"caller":{"features":{"caller_identification":true,"progressive_call_results":true,"call_canceling":true}},"callee":{"features":{"caller_identification":true,"progressive_call_results":true,"call_canceling":true}}},"authmethods":[],"authid":"anonymous"}])
2018-09-08T07:20:34.2863310 info       [Thruway\RealmManager 1812] Got prehello...
2018-09-08T07:20:34.2863440 debug      [Thruway\RealmManager 1812] Creating new realm 'realm1'
2018-09-08T07:20:34.2875190 debug      [Thruway\RealmManager 1812] Adding realm 'realm1'
2018-09-08T07:20:34.2898050 debug      [Thruway\Transport\RatchetTransportProvider 1812] onMessage: ([32,5799645875876444,{},"com.myapp.hello"])
2018-09-08T07:20:34.2904330 debug      [Thruway\Subscription\SubscriptionGroup 1812] Added subscription to 'exact':'com.myapp.hello'
2018-09-08T07:20:34.2905620 debug      [Thruway\Transport\RatchetTransportProvider 1812] onMessage: ([16,3149386944896931,{"acknowledge":true},"com.myapp.hello",["Hello, world from PHP!!!"]])
2018-09-08T07:20:34.2907040 debug      [Thruway\Transport\RatchetTransportProvider 1812] onMessage: ([64,3904229972015909,{},"com.myapp.add2"])
2018-09-08T07:20:34.2915070 debug      [Thruway\Transport\RatchetTransportProvider 1812] onMessage: ([48,4597463936048137,{},"com.myapp.add2",[2,3]])
2018-09-08T07:20:34.2930660 debug      [Thruway\Transport\RatchetTransportProvider 1812] onMessage: ([70,6219899842080365,{},[5]])

Routerの実装

router.php
<?php

require_once './vendor/autoload.php';

use Thruway\Peer\Router;
use Thruway\Transport\RatchetTransportProvider;

$router = new Router();

$transportProvider = new RatchetTransportProvider("127.0.0.1", 9090);

$router->addTransportProvider($transportProvider);

$router->start();

ThruwayのExampleにあるSimpleWsServer.phpのほぼ全コピーです。

これだけでws://127.0.0.1:9090でアクセス可能なRouterの実装が完了します。

Clientの実装

Clientはautobahn.jsに任せるのでひたすらhtmlとjsです。

client用のautobahn.min.jsを手に入れる
bower install autobahn

bowerでinstallしたパッケージはbower_componentsに入ってくれるのでこれを<script src='...'>で読み込めば使えるようになります。

というわけでチャット欄を設けてjsを読むhtmlを用意しましょう。

chat.html
<html>
  <head>
    <meta charset='utf-8'>
    <title>chat</title>
  </head>

  <body>
    <h3>Chat</h3> 
    <ul id='chat-list'></ul>
    <input id='speech' type='text'>
    <button onclick='chat()'>chat</button>

    <script src="/bower_components/autobahn/autobahn.min.js"></script>
    <script src="/chat.js"></script>
  </body>
</html>

最低限。

最後にchat.htmlに読ませるjsを作って完成です。

chat.js
const chat_url = 'php.chat';
var conn;
(function(){
  conn = new autobahn.Connection({url: 'ws://127.0.0.1:9090', realm: 'realm1'});
  conn.onopen = function(session){
    function received_chat(message){
      document.getElementById('chat-list').innerHTML += '<li>' + message[0] + '</li>';
    }
    session.subscribe(chat_url, received_chat);
  }
  conn.open();
}());

function chat(){
  const chat = document.getElementById('speech').value;
  conn.session.publish(chat_url, [chat], null, {exclude_me: false});
}

autobahnautobahn.min.js内で定義された変数です。autobahnが定義している各メソッドやクラスはこいつ経由で参照します。

new autobahn.Connection()でWebSocket通信のurlやrealmを指定します。実際にconnectするにはconn.open()です。

conn.onopenで、connectionを確立した時に処理する関数を指定します。今回はsession.subscribephp.chatチャンネルでpublishイベントがあった際の挙動を指定しています。

function chat()はchatボタンを押したときの挙動です。入力フォームの値をphp.chatチャンネルにpublishします。

{exclude_me: false}というのは、publishした本人もpublishイベントを受け取るためのオプションです。これがないとpublishした本人は自分の発言がチャット欄に流れて来なくなります。

以上で実装終了です。

動かす

php -S localhost:9999 | php router.php

任意のブラウザでhttp://localhost:9999/chat.htmlに行けばもうそこはチャットルームです。

Thruway.gif

まとめ

ほとんどautobahnの説明でしたがたったこれだけのコードでWAMPv2に則ったチャットアプリを実装できてしまいました。

後は発言をredisに保存するなりxss対策するなり部屋を分割するなりすればいいと思います。

phpによるclientサイドの実装はThruwayのREADME.mdの実例で分かりやすく説明しています。autobahnと見た目はあまり変わりません。

phpでWebsocket通信したいときには是非Thruwayの採用をご検討ください。

  1. 2018/09/08

11
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?