phpjquerycometlong-pollingflush

Back-end not flushing correct data


I'm trying to put together a really simple comet test page. I have a main client page with a div ID of #TextHistory. The JavaScript in this page should create an open connection to back-end.php which uses JavaScript to update a value and flush it back out to the client page. I'm really not sure if I'm doing this right at all... I've based it on How do I implement basic "Long Polling"?.

What I'm finding is on the client page (Firefox) it looks like the back-end.php isn't returning anything and times out after 10 seconds. If I take out the PHP loop in the back-end.php it constanty returns "DefaultData" and appends straight away to the TextHistory DIV. I feel like I'm close but doing something wrong. Sorry for the strange formatting here, it looks like some header and PHP tags aren't allowed.

Client Side:

 $(document).ready(function() {

    waitForMsg(); /* Start the inital request */


});

     
    function addmsg(type, msg){
        /* Simple helper to add a div.
        type is the name of a CSS class (old/new/error).
        msg is the contents of the div */
        $("#TextHistory").append(
            "<div class='msg "+ type +"'>New MSG: "+ msg +"</div>"
        );
    }

    function waitForMsg(){
        /* This requests the url "msgsrv.php"
        When it complete (or errors)*/
        $.ajax({
            type: "GET",
            url: "backend.php",

            async: true, /* If set to non-async, browser shows page as "Loading.."*/
            cache: false,
            timeout:50000, /* Timeout in ms */

            success: function(data){ /* called when request to barge.php completes */
                addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/
                setTimeout(
                    'waitForMsg()', /* Request next message */
                    1000 /* ..after 1 seconds */
                );
            },
            error: function(XMLHttpRequest, textStatus, errorThrown){
                addmsg("error", textStatus + " (" + errorThrown + ")");
                setTimeout(
                    'waitForMsg()', /* Try again after.. */
                    "15000"); /* milliseconds (15seconds) */
            },
        });
    };

    
    </script>


 </head>

 <body>


  <div id="container">

    <div id="main">

     <h2>Text Scrolling Test</h2>


      <div id="TextHistory">

       <p>First default line of text</p>
       <p>Second default line of text</p>

      </div>

    </div>

  </div>



 </body>


</html>

Backend.php which is called:

<---php start --->

session_start();

  header("Cache-Control: no-cache, must-revalidate");

  header("Expires: Mon, 26 Jul 2012 05:00:00 GMT");

flush();

<---php end --->

then default HTML doctype, head, meta, jQuery include,

Then in the body:

 <div id="LastMsg">DefaultData</div>

<---PHP Start --->

     $OutputMsg = "Initial";


    while (true) {

    $OutputMsg .= "Something.";

  echo "

      <script type=\"text/javascript\">
        $('#LastMsg').html(\"<p>$OutputMsg</p>\");
      </script>
   
     ";



      flush(); // Ensure the Javascript tag is written out immediately
      sleep(1);
    }
    
  
    
  <---PHP END --->

Solution

  • You should consider using flush() with output buffering. PHP does some weird things internally, so you normally are required to use both.

    ob_start();

    while (true) {

    if ($newcontent) { echo 'my new content'; ob_flush(); flush(); }

    sleep(1); }

    Although, your approach to long polling is incorrect. You don't want to keep the browser connection open forever, only until there is data to push to the client. Once the data is received, you close the connection, and re-open it. It basically has to do with memory/connection management.