

# やっていること

PHPでCometによるチャットシステムを作成しています。  
// このご時世になんでWebSocketを使わないんだ？ という話はなしでお願いします。  
概ねはうまく動くのですが、時々PHPが情報を吐き出してくれないことがあり、どうにかならないかお尋ねしたいです。

# 構造

ページは **input.html** , **output.html** , **comet.php** , **chat.txt** ,
**filesize.txt** の5枚構成です。

  1. **output.html** が **comet.php** をajax通信で呼び出しロングポーリング
  2. **input.html** でチャット文章を入力し **chat.txt** に保存
  3. **comet.php** 内で **chat.txt** のファイルサイズを監視し、ファイルサイズが大きくなったらチャットに新しい文が入力されたと判断
  4. **comet.php** で新しく入力された **chat.txt** の内容を取得し、 **output.html** に渡す
  5. **output.html** がチャットの内容を受け取り、画面に出力する

という動きを取ります。

基本的に **input.html** に多人数がアクセスし、 **output.html** には1人がアクセスする、という想定です。  
// 今回、input.htmlは関係しないものと思うのでこれ以降出てきませんが、もし解決の可能性がinput.htmlにあるようでしたらまた追記します。

# コード

**output.html** 内の`func()`関数内でJavaScript（jQuery）によるajax通信を実行し、 **comet.php**
でロングポーリングしながら（という言い方が正しいかわかりませんが）、チャットの更新があった場合に表示します。

<output.html>

[code]

    <script>
        function func() {
            $.ajax({
                type: "POST",
                url: "comet.php",
                chche: false,
                data: { 'hoge': fuga },
                dataType: "json"
            }).done(function (d) {
               console.log('received');  // (★)
               // 表示処理
               func();  // 再帰呼び出しで実質無限ループ
            }
            ).fail(function (XMLHttpRequest, status, e) {
                // エラー処理
            });
        }
        
        $(function () {
           func();
        });
    </script>
    
[/code]

<comet.php>

[code]

    $time = 0;
    $oldfs = 0;
    $newfs = 0;
    $result = "{}";  // 最終的にこの変数が output.html に渡されます
    
    while($time < 30) {  // 30秒経ったらループを抜ける
        clearstatcache();
            
        $oldfs = file_get_contents('filesize.txt');  // (1) 以前のファイルサイズ
        $newfs = filesize('chat.txt');  // (2) 現在のファイルサイズ
    
        if($oldfs < $newfs) {  // 現在のファイルサイズが以前より大きい ＝ チャットに新しく書き込まれた
            file_put_contents('filesize.txt', $newfs, LOCK_EX);  // (3) 現在のファイルサイズで以前のファイルサイズを上書き
            $result = json_encode(piyo);
            echo $result;  // (4) output.htmlにデータ受け渡し
            return false;
        }
        sleep(1);  // 負荷軽減
        $time++;
    }
    
    echo $result;  // 30秒経って何も更新がなかったら一度output.htmlに更新がなかったことを伝える
    return false;
    
[/code]

**comet.php** の動きについて補足します。

  * (1) では、以前の更新時に使っていた、 **chat.txt** のファイルサイズを取得（初期値は0）します。
  * (2) では、現在の **chat.txt** のファイルサイズを取得（初期値は0）します。
  * (3) は現在のファイルサイズ`$newfs`が、以前のファイルサイズ`$oldfs`を上回っていたときに、以前のファイルサイズを保存するファイル **filesize.txt** を現在のファイルサイズで上書きします。この値が、次の走査のときの`$oldfs`に代入されます。
  * (4) のecho文で、`$result`の内容が **output.html** に返されます。この`$result`は、`piyo`という配列をjson形式にしたものです。
  * 30秒経ったときにwhile文を抜けるようにしているのはconnection lostを回避するためです（これが正しいのか、そもそも必要なのか特に調べていませんが……）

# 問題点（解決したいこと）

**input.html** からチャットの入力があったとき、 **comet.php** のコード(4)部分でその内容が **output.html**
に渡され画面に出力される、というのが想定ですが、これがたまに動かなくなり、 **input.html** での入力が **output.html**
に表示されなくなります。

原因が分からず、できるだけ切り分けを行ってみたのですが、この問題が起きたとき、

  * **chat.txt** には間違いなく入力された文章が保存されている
  * **comet.php** のコード(3)部分で、ファイルサイズは最新のものに間違いなく更新され、 **filesize.txt** に保存されている
  * **output.html** のコード(★)部分で、`console.log('received');`が動いていない
  * **output.html** の`$.ajax`内で、`.fail`によるエラー処理は発生していない
  * この問題が生じたあと、新しい文章がチャットに入力されると、それは表示されるときもあるし表示されないときもある

ということは把握しています。  
この問題が発生するのは、チャットの全入力数に対して体感2割くらいの確率です。

この切り分けが本当に正しく行われているのであれば、問題は **comet.php** 内の  
`$result = json_encode(piyo);`か、その直後の`echo $result;`、  
もしくは **output.html** 内の`$.ajax`内で問題が発生していることになります。

しかし「絶対に動かないわけではなく、たまに動かなくなる」という状況ゆえ、決定的な原因を突き止めることが出来ておらず、途方に暮れています。

この問題を解決する方法について、皆様のお力添えをいただきたいです。

# 環境

PHPのバージョンは7.4.21および7.4.28です。両方で同じ問題が発生しています。

# さいごに

こういうサイトで質問することに慣れていないため、不躾な点ありましたらご容赦ください。また不足している情報がありましたら追記させていただきます。  
皆様のお力添えを、どうぞよろしくお願い申し上げます。


CC BY-SA 4.0
2022-04-05T00:29:11.770
88171
2022-04-05T00:35:21.983
2022-04-05T00:35:21.983
30625
30625
question
javascript php jquery ajax
PHPでCometを実装したとき、たまにデータを出力しない