【WebSocket】PHP/Ratchetを使ってチャットページを作ってみた

2022年11月15日

WebSocket通信を実装できる「phpのライブラリRatchet」を使ってチャットページを作ってみました。

関連記事
【WebSocket】PHP/Ratchetを使ってチャットページを作ってみた
【WebSocket】NginxでRatchetをSSL/wss化

チャットページのサンプル

チャットページ – テキストメッセージ

WebSocketとは

WebSocketとはWEBページの更新をしなくても、リアルタイムでデータ通信できるプロトコルです。

ブラウザでページにアクセスする / 更新する・・・WEBページを見る 
ブラウザの画面上でボタンを押すなどのアクション・・・WebSocketによるリアルタイム双方向通信
WebSocket通信とは
WebSocketとは

また、WebSocketにはデータの暗号化を行わない通信「ws」と、暗号化するセキュア通信「wss」があります。

今のブラウザのセキュリティ上、「http」と「https」を一つの同じブラウザ上で同時に通信させることができません。

WebSocketについても同じで、

「http」でWEBページにアクセスするならWebSocketも「ws」で通信させる必要があり、

「https」でアクセスするならwebsocketのセキュア通信プロトコル「wss」で通信させる必要があります。

非暗号化/暗号化プロトコルを合わせる必要がある
暗号化しない通信         ・・・http / ws
暗号化するセキュア通信・・・https / wss

WebSocketの通信の仕組み

WebSocketは、WEBページアクセス時にWebSocketのコネクションを確立し、

その後はWebSocketプロトコル単独でデータをやり取りします。

サーバー側には

WEBブラウザにWEBページを返す「WEBサーバー」と、

WebSocket通信を返す「WebSocketサーバー」が必要になります。

WebSocketを実装するphpのライブラリ「Ratchet」

ここで使っているphpのWebSocket実装ライブラリ「Ratchet」についてですが、

現在、wssサーバーとして立てることができないようです。

基本的にはWEBページをhttpのみで運用するしかありませんが、

WebサーバーをNginxにすれば、Nginxのリバースプロキシでwssをwsに変換し、

「Ratchet」でもSSL / wss 通信を実現することができます。

WebSocket - php - Ratchet
WebSocket – php – Ratchet

開発環境 MAMPへの実装手順

まずは、MAMPという開発環境を使った手順について書いてみたいと思います。

参考サイト
Ratchet - PHP WebSockets
Ratchet - Tutorial: Your first app

MAMP、Composerのインストールがまだの場合は下記を参考にしてください。

関連記事
【Mac】に【MAMP】をインストールする
関連記事
【Mac】にComposerをインストールする

ratchetインストール

MAMPフォルダのhtdocsに「ratchet」というフォルダを作ります。

Macのターミナルを起動して、ratchetフォルダに移動します。

 % cd /Applications/MAMP/htdocs/ratchet

Composerを使って、ratchetをインストールします。

 % pwd
/Applications/MAMP/htdocs/ratchet

 % composer require cboden/ratchet

〜〜〜〜
  - Installing cboden/ratchet (v0.4.4): Extracting archive
7 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
13 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

「ratchet」フォルダに

2つのファイル「composer.json」「composer.lock」と、

1つのフォルダ「vendor」ができます。

chat-server.phpの作成

「ratchet」フォルダに移り、

「bin」というフォルダを作り、

「bin」フォルダ内に「chat-server.php」というファイルを作ります。

「chat-server.php」に下記のように記述します。

<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;

    require dirname(__DIR__) . '/vendor/autoload.php';

    $server = IoServer::factory(
        new HttpServer(
            new WsServer(
                new Chat()
            )
        ),
        8080
    );

    $server->run();

Chat.phpの作成

「ratchet」フォルダに「src」フォルダを作って、

「src」フォルダ内に「Chat.php」というファイルを作ります。

※ファイル名のChat.phpのCは大文字にします。

「Chat.php」に下記のように記述します。

<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat 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();
    }
}

composer.jsonの書き換え

composer.jsonをテキストエディタで開いて、下記のように書き換えます。

{
    "autoload": {
        "psr-4": {
            "MyApp\\": "src"
        }
    },
    "require": {
        "cboden/ratchet": "^0.4"
    }
}

src/階層配下がMyAppというnamespaceとなり、

MyApp\Chatは「src/Chat」ディレクトリの下に、Modelクラスが存在するという書き方になります。

「composer.json」を書き換えたら、composer dump-autoloadコマンドでバンドルを追加します。

% composer dump-autoload
Generating autoload files
Generated autoload files

index.htmlの作成

「ratchet」フォルダに「index.html」を作成します。

「index.html」は下記リンクよりダウンロードできます。

jQuery「jquery-3.6.0.min.js」を下記サイトよりダウンロードして、

「htdocs/js」フォルダに保存します。

Download jQuery | jQuery

ダウンロードしたjQueryのバージョンに合わせて、index.htmlを書き換えてください。

<script src="../js/jquery-3.2.1.min.js"></script>

MAMPの起動

MAMPを起動して、右上のStartボタンを押します。

MAMP Start

WebSocketサーバー(chat-server.php)の起動

MacのターミナルからMAMPのphpで「chat-server.php」を起動する

 % cd /Applications/MAMP/bin/php/php8.0.8/bin/

% php /Applications/MAMP/htdocs/ratchet/bin/chat-server.php

チャットルームに入室する

ブラウザのアドレスバーに「http://localhost/ratchet/index.html」と入力してアクセスします。

ブラウザのConsoleメッセージに「Connection established!」と表示されていればOKです。

ブラウザのタブをもう一つ開いて、同じURLにアクセスします。

すると、最初に開いた方のチャットに、「info:someone join this room」と表示されます。

これでチャットルーム完成です。

MacのターミナルにもWebSocket通信のログが出力されています。

WebSocket通信のログ
WebSocket通信のログ

参考サイト

Ratchet - PHP WebSockets
Ratchet - Tutorial: Your first app

PHPでWebSocket – Qiita

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

php,WebSocketphp,WebSocket

Posted by sei