PHPで簡易チャット

勉強としてPHPでチャットを作れるかといろいろ調べていたところ、Comet(コメット)と言う技術があるらしいのでそちらを利用して作成してみます。

Comet(コメット)は、リクエストを受けたら直ぐにレスポンスを返さずに待機して、なんらかのイベントが発生したらレスポンスを返すというような事ができるそうです。

今回の場合だと、ページを開いたときにサーバー側にリクエストを送り、リクエストを受けたサーバーでチャットログが更新されるまで待機して、更新されたら最新のログを返すということができます。これによりサーバーへのアクセス数を少なくできます。

ではいきなりですが、まずはじめにPHPの処理を書きます。

<?php
$request_method = filter_input(INPUT_SERVER, "REQUEST_METHOD");

if($request_method === "POST")
{
    //送信されたメッセージを取得
    $data = file_get_contents("php://input");
    $message =  htmlspecialchars($data)."\r\n";
    
    //ログファイルに追記する
    if(file_put_contents("./chat.log",$message,FILE_APPEND) === false){
        echo '';
    } else {
        
        //追記できた場合は追記後の内容を返す
        $file = file_get_contents("./chat.log");
        
        if ($file !== false) {
            echo nl2br($file);
        } else {
            echo '';
        }
    }
}
<?php
//ファイルが存在する場合はその内容を返す
if (file_exists("./chat.log")) {
    $file = file_get_contents("./chat.log");

    if ($file !== false) {
        echo nl2br($file);                    
    } else {
        echo "";
    }            
} else {
    echo "";
}
<?php
$is_not_exists = ''; //ファイルが存在しなかったかどうか
$before_file = ''; //変更前のファイルの内容

//10秒に一回ループする
while (true) {
    if (file_exists("./chat.log")) {
        
        //リクエストのはじめにログフの内容を取得する
        if (empty($before_file)) {
            
            //ログを取得
            $before_file = file_get_contents("./chat.log");

            //ループの途中でログファイルが作成された場合はその内容を返す
            if ($is_not_exists) {
                echo nl2br($before_file);
                break;            
            }

            continue;
        }

        //ログを取得
        $file = file_get_contents("./chat.log");

        if ($file !== false) {
            
            //はじめに取得した内容から変更がされている場合はその内容を返す
            if ($before_file !== $file) {
                echo nl2br($file);
                break;
            }
        }    
    } else {
        //ファイルが存在しない
        $is_not_exists = true;
    }

    //10秒間処理をとめる
    sleep(10);
}

以下ざっくりとした説明です。

sendMessage.phpは、送信されたメッセージをchat.logに書き込みます。

getLog.phpは、ページ読み込み完了時に実行されて最新のチャットログを返します。

updateLog.phpは、chat.logが更新されるまでループで待機し、更新されたらファイルの内容を返します。

 

次にHTMLを用意します。

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>チャット</title>
    </head>
    <body>
        <div id="chat_log">
        </div>
        <input type="text" size="50" id="message" />
        <button type="button" id="send">送信</button>            
    </body>
</html>

そしてjavascriptです、

        <script type="text/javascript">
            window.onload = function(){                
                getLog();  
                
                //送信ボタン押下時
                document.getElementById("send").addEventListener("click",function(){
                    var text = document.getElementById("message");

                    if(text.value !== null && text.value !== ""){
                        sendMessage(text.value); //メッセージ送信
                        text.value = ''; //テキストボックスをクリアする
                    }
                });

            };
            
            //メッセージの送信処理
            function sendMessage(message) {
                var xhr = new XMLHttpRequest();
                xhr.open("POST","/chat/sendMessage.php");
                xhr.send(message); //メッセージを送信する

                xhr.onreadystatechange = function () {
                    //受信時の処理
                    if(xhr.status === 200 && xhr.readyState === 4){
                        //返された最新のチャットログを画面に表示
                        document.getElementById("chat_log").innerHTML = xhr.responseText;
                    }                                    
                };                
            }

            //初期表示時のログ取得
            function getLog() {
                var xhrGet = new XMLHttpRequest();
                xhrGet.open("GET","/chat/getLog.php");
                xhrGet.send();                

                xhrGet.onreadystatechange = function () {
                    //受信時の処理
                    if(xhrGet.status === 200 && xhrGet.readyState === 4){               
                        //返された最新のチャットログを画面に表示
                        document.getElementById("chat_log").innerHTML = xhrGet.responseText;
                        //再度リクエストを送る
                        updateLog();
                    }                                    
                };
            }
            
            //ログを随時更新する
            function updateLog() {
                var xhrUpdate = new XMLHttpRequest();
                xhrUpdate.open("GET","/chat/updateLog.php");
                xhrUpdate.send();                

                xhrUpdate.onreadystatechange = function () {
                    //受信時の処理
                    if(xhrUpdate.status === 200 && xhrUpdate.readyState === 4){
                        //返された最新のチャットログを画面に表示
                        document.getElementById("chat_log").innerHTML = xhrUpdate.responseText;
                        //再度リクエストを送る
                        updateLog();
                    }                                    
                };                
            }            
        </script>

sendMessage()は、送信ボタンが押されたら、サーバー側にメッセージを送信し、返された最新のログを画面に表示する。

getLog()は、ページ読み込み完了時に実行され、最新のログを取得した後updateLog()を実行する。

updateLog()が前述のCometを利用した処理で、下記の処理を繰り返し行っています。

  1. javascriptでサーバー側にリクエストを送る
  2. 受け取ったサーバー側のupdateLog.phpが実行され、ログが更新されるまで待機
  3. ログが更新されたら、ログの内容をクライアント側へ返す
  4. javascriptで返されたログの内容を画面表示
  5. 再度updateLog()を実行し、(1)から順に処理を行う

 

以上がComet(コメット)を利用したチャットの作り方でした。

利用できる場面は少なそうですが、良い勉強になったかと思います。

参考URL:http://rewish.jp/blog/tech/php_with_jquery_comet