Search code examples
phpjquerylong-polling

Issues with long polling and sessions (chat)


I made a friends chat that uses textfiles to store data and it all works more or less except when I sign in and write something to someone, nothing pops up (but the text is stored in the appropriate text file), then when I refresh the page it is ok from THEN ON, but on the other browser as the other user I have to also refresh the page in order for it to work normally both ways.

Basically, every time I log in I have to click the name of the person I want to chat with, then a window pops out and THEN i have to refresh or else it doen\sn't work.

I guess I have to kind of refresh the page whenever I click on a friend and want to chat with him and that it is a session problem.

here is home.php (users are redirected here when they log in on index.php page)

<?php
session_start();

if (!isset($_SESSION['user'])) {
    header("Location: index.php");
    exit();
}

?>
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">

<title></title>
<style type="text/css">@import 'custom_chat.css';</style>
</head>

<body>

<h2>Hello, <?php echo $_SESSION['user']; ?></h2>
<hr>
<p><b>CONTACTS:</b></p>
<?php
require_once 'dbc.php';
$u = $_SESSION['user'];

$q = "SELECT user_id FROM users WHERE username='$u'";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);

// current user id
$uid = $row[0];

$q = "SELECT u.username FROM users AS u, friends AS f 
      WHERE (f.f1 = '$uid' OR f.f2 = '$uid') AND (f.f1 = u.user_id OR f.f2 = u.user_id) AND (u.username != '$u')";
$r = mysqli_query($dbc, $q);


while ($row = mysqli_fetch_assoc($r)) {
    echo '<div class=chat_contacts>';
    echo '<div class='.$row['username'].'>';
    echo '<div class=inner>';
    echo '<div class=inner_chat></div>';
    echo '<form>
              <textarea class=chat_text></textarea> 
          </form>       
          ';
    echo '</div>'; // end .inner
    echo '<a href="#" class='. $row['username'] .'>'.$row['username'] .'</a>
          </div>';
    echo '</div>'; // end .chat_contacts
}

?>

<p><a href="index.php">HOME</a></p>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
<script type="text/javascript">

var nc = '<?php echo $u ?>';

// toggle chat window
$('.chat_contacts a').click(function() {
    $(this).prev('div.inner').toggle();
    var tc = $(this).attr('class');
    $(this).parent().parent().addClass(nc+tc);
    $('textarea').focus(); // MD maybe
    return false;
});

// call main chat function
$(function () {
    updateChat(); 
}); // end ready

//update on enter
$('textarea.chat_text').keypress(function(e) {
    $this = $(this); // textarea
    if (e.which == '13') {
        insertChat();



        return false;
    }
});

function insertChat() {
    var text = $this.val();
    $this.val('');
    var ru = $this.parent().parent().parent().attr('class');
    $.post('insert.php',{text:text, ru:ru}, function(data) {
        if (data) {
            alert(data)
        }
    });
}

var timestamp = 0;
function updateChat() {
    $.ajax({
        type: 'GET',
        url: 'update.php?timestamp=' + timestamp,
        async: true,
        cache: false,

        success:function(data) {
            // alert(data);
            var json = eval('('+data+')');
            // if (json['msg'] != null) {
                $('.chat_contacts.'+nc+json['nru']+' .inner_chat').append('<p>'+json['msg']+'</p>'); // MD
            // }
            timestamp = json['timestamp'];
            setTimeout('updateChat()', 1000);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            // alert('error '+textStatus+'('+errorThrown+')');
            setTimeout('updateChat()', 1000);
        }
    });
}

</script>
</body>
</html>

update.php

<?php
session_start();
require_once('dbc.php');
error_reporting(E_ALL ^ E_NOTICE);
set_time_limit(0);

$ou = $_SESSION['user'];
$ru = $_SESSION['ru'];
session_write_close();

$q = "SELECT * FROM chats WHERE 
      (chats.f1='$ru' AND chats.f2='$ou') OR (chats.f1='$ou' AND chats.f2='$ru') ORDER BY time DESC LIMIT 1";
$r = mysqli_query($dbc, $q);

// $filename = 'vojaolja.txt';
$q = "SELECT user_id FROM users WHERE username='$ou' 
      ORDER BY user_id DESC LIMIT 1";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);
$fu = $row[0];

$q = "SELECT user_id FROM users WHERE username='$ru' ORDER BY user_id DESC LIMIT 1";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);
$su = $row[0];

$q = "SELECT username FROM users WHERE username='$ru' ORDER BY user_id DESC LIMIT 1";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);
$nru = $row[0];

if ($fu < $su) {
    $filename = $fu.$su.'.txt';
} else {
    $filename = $su.$fu.'.txt';
}

$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$currentmodif = filemtime($filename);

while ($currentmodif <= $lastmodif) {
    usleep(10000);
    clearstatcache();
    $currentmodif = filemtime($filename); 
}

$response = array();

$data = file($filename);
$line = $data[count($data)-1];

$response['msg'] = $line;
$response['nru'] = $nru;
$response['timestamp'] = $currentmodif;

echo json_encode($response);

?>

Also, if someone wants to reproduce this on their own computer, I can post all the code here, it is just a few pages, it can be setup together with the database in literally 2 minutes.

EDIT:

as soon as I login, i see the following in the console:

http://localhost/x_super_chat/update.php?timestamp=0&_=1374509358392 (plus the rolling thingy, it is waiting)

Then i click on a friend's name, window pops up, I write something and i get this in the console:

http://localhost/x_super_chat/insert.php

AND THEN WHEN I REFRESH AGAIN (when it actually starts working) I get the following in the console.

http://localhost/x_super_chat/update.php?timestamp=0&_=1374509491493
http://localhost/x_super_chat/update.php?timestamp=1374509435&_=1374509493231 + the waiting thingy icon, it is waiting

So it changes after refresh, I need what I get after refresh to be there as soon as I log in.

EDIT 2: (after Pitchinnate's answer)

As soon as I login, I see this in the console:

http://localhost/x_super_chat/update.php?timestamp=0&_=1374566749185 (plus the waiting animation)

Then I write something to the other person (say John), and I get the following:

http://localhost/x_super_chat/update.php?timestamp=0&_=1374566749185
http://localhost/x_super_chat/insert.php
http://localhost/x_super_chat/update.php?timestamp=0&_=1374566817682
http://localhost/x_super_chat/update.php?timestamp=1374565160&_=1374566817740
http://localhost/x_super_chat/update.php?timestamp=1374566817&_=1374566817801 (plus waiting animation)

THEN when I write something on the other side as John, I get the following: (this is from chrome so it is not the same as the console in firebug):

http://localhost/x_super_chat/update.php?timestamp=0&_=1374566987051
http://localhost/x_super_chat/insert.php
http://localhost/x_super_chat/update.php?timestamp=1374566995&_=1374567004175
http://localhost/x_super_chat/update.php?timestamp=1374567004&_=1374567004215

Solution

  • One thing you can try is cancelling your long poll upon insert, create a global javascript variable outside your update function var myajax;

    myajax = $.ajax({
        type: 'GET',
        url: 'update.php?timestamp=' + timestamp,
    

    Then on insert:

    function insertChat() {
        myajax.abort();
        var text = $this.val();
        $this.val('');
        var ru = $this.parent().parent().parent().attr('class');
        $.post('insert.php',{text:text, ru:ru}, function(data) {
            if (data) {
                updateChat();
            }
        });
    }