Ratchetを使いWeb上でリアルタイムチャットを実装する

その他プログラミング

通常の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';
__DIR__読み込んだファイルがあるディレクトリ名
dirname(xxx)xxxの存在するディレクトリ名

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/

コメント

  1. Ryuji より:

    初めまして、こちらの記事を参考に挑戦してみたのですが、
    localhost/MyChat.html
    でアクセスしても、「このサイトにアクセスできません」と表示されてしまいます。

    $ php webserver.php

    までは特に問題なくいけております。
    単純にアクセス先を間違えているのでしょうか?

    ディレクトリ構成は、以下になります。

    .
    ├── MyChat.html
    ├── MyChat.php
    ├── composer.json
    ├── composer.lock
    ├── composer.phar
    ├── vendor

    もしお時間ありましたらアドバイス頂けると幸いです。

    • kajindows より:

      お使いの環境でウェブサーバーが正しく動作していないか、ドキュメントルートが異なるのかもしれません。
      UbuntuでApacheを利用した例では、ドキュメントルートは/var/www/htmlなので、/var/www/html/webchat/Mychat.htmlという構成にした場合、localhost/webchat/MyChat.htmlにアクセスする必要があります。

タイトルとURLをコピーしました