LoginSignup
17
33

More than 3 years have passed since last update.

PHPでWebSocket

Last updated at Posted at 2020-08-01

PHPでWebSocketやっていきます

プロジェクト作成

Composerプロジェクトをつくります
Composerをインストールしていない方はインストールしてください
Composerをインストールする

適当なフォルダをつくって
コマンドラインでcdして行きます
コマンドラインで
composer init
これでcomposer.jsonできます
今回はRatchetを使っていきます
Ratchet (http://socketo.me/)
コマンドラインで
composer require cboden/ratchet
これでRatchetが使えるようになります

srcフォルダをつくります

composer.jsonのautoload修正します
composer.jsonは下記にします

composer.json
{
    "autoload" : {
        "psr-4" : {
            "App\\" : "src"
        }
    },
    "require": {
        "cboden/ratchet": "^0.4.3"
    }
}

コマンドラインで
composer dump-autoload
これで修正したautoloadが反映されます

フォルダ構成は下記になります

`-- sample
    |-- src
    |-- vendor
    `-- composer.json

ファイル作成

(1) srcフォルダ配下にChat.php作成

Chat.php
<?php
namespace App;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface {

    protected $clients;

    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        foreach ($this->clients as $client) {
            $data = ['msg' => $msg];
            if ($from === $client) {
                $data['position'] = 'right';
            } else {
                $data['position'] = 'left';
            }
            $client->send(json_encode($data));
        }
    }

    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        $conn->close();
    }
}

webSocket接続してきたら自動的にonOpenが実行されます。今回は$this->clientsにコネクションを追加しています
クライアントがデータをsendしてきたら自動的にonMessageが実行されます。今回はjsonを返すようにしています

(2) srcフォルダ配下にwsServer.php作成

wsServer.php
<?php
namespace App;

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use App\Chat;

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

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

$server->run();

webSocketのエントリポイントになります
8282は今回WebSocketで使うポートです。firewallで許可しているポートにしてください
先ほど作成したChatクラスを与えてWebSocketサーバーをrunします

(3) HTTPサーバーの公開フォルダにws.html作成

ws.html
<html>
<head>
<title>sample</title>
<style type="text/css">
.container {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
}
.msg-log {
    width: 100%;
    height: 92%;
    vertical-align:top;
    box-sizing: border-box;
    padding: 0px;
    border: black solid 1px;
    overflow-y: scroll;
}
.input-area {
    width: 100%;
    box-sizing: border-box;
}
.msg {
    width: 90%;
    height: 8%;
    vertical-align:top;
    box-sizing: border-box;
    padding: 0px;
    float: left;
}
.btn {
    width: 10%;
    height: 8%;
    vertical-align:top;
    box-sizing: border-box;
    padding: 0px;
}
.receive-msg-left {
    border-radius: 10px;
    border: black solid 1px;
    padding: 10px;
    margin: 10px;
    display: inline-block;
    float: left;
}
.receive-msg-right {
    border-radius: 10px;
    border: black solid 1px;
    padding: 10px;
    margin: 10px;
    display: inline-block;
    float: right;
    background-color: #00FF00;
}
.br {
    clear: both;
}
</style>
<script type="text/javascript">

  var conn = "";

  function open(){

      conn = new WebSocket('ws://localhost:8282');

      conn.onopen = function(e) {
      };

      conn.onerror = function(e) {
        alert("エラーが発生しました");
      };

      conn.onmessage = function(e) {
          var data = JSON.parse(e.data);
          var divObj = document.createElement("DIV");
          if (data["position"] == "left") {
              divObj.className = 'receive-msg-left';
          } else {
              divObj.className = 'receive-msg-right';
          }
          var msgSplit = data["msg"].split('\n');
          for (var i in msgSplit) {
              var msg = document.createTextNode(msgSplit[i]);
              var rowObj = document.createElement("DIV");
              rowObj.appendChild(msg);
              divObj.appendChild(rowObj);
          }

          var msgLog = document.getElementById("msg_log");
          msgLog.appendChild(divObj);

          var br = document.createElement("BR");
          br.className = 'br';
          msgLog.appendChild(br);

          msgLog.scrollTop = msgLog.scrollHeight;

      };

      conn.onclose = function() {
          alert("切断しました");
          setTimeout(open, 5000);
      };

  }

  function send(){
      conn.send(document.getElementById("msg").value);
  }

  function close(){
      conn.close();
  }

  open();

</script>
</head>
<body>
    <div class="container">
        <div id="msg_log" class="msg-log"></div>
        <div class="input-area">
            <textarea id="msg" class="msg"></textarea>
            <button class="btn" onclick="send();" >送信</button>
        </div>
    </div>
</body>
</html>

conn = new WebSocket('ws://localhost:8282');で接続してます。8282は先ほどwsServer.phpに書いたポートです
conn.send(document.getElementById("msg").value);でwebSocketサーバーにデータ送信しています
conn.onmessageはwebSocketサーバーからsendがあった場合に自動的に実行されます

動作確認

コマンドラインで
srcフォルダにcdして
php wsServer.php
これでWebSocketサーバーが起動しました

HTTPサーバを起動し
HTTPサーバーの公開フォルダにつくったws.htmlにブラウザでアクセスしてみましょう
http://localhost/ws.html
ChromeとFirefoxでアクセスしてみましょう

Chromeでテストクロームと入力し、送信ボタンをクリックします
Firefoxでテストファイヤーフォックスと入力し、送信ボタンをクリックします

動きました

Chromeの画面
a.png

Firefoxの画面
b.png

RatchetをLaravelで使う

LaravelでRatchetを使ってWebSocketする方法は下記記事に書きました
LaravelでWebSocket

17
33
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
17
33