Social elements like messages require constant polling to the database to see if they have a new message / friend request. There are a few techniques you can use, but my goal was to be as lightweight as possible.
$db = mysqli_db::init();
$total_unread = $db->fetch_singlet('
SELECT COUNT(DISTINCT messages.messages_id) AS total
FROM messages
INNER JOIN members ON messages.join_members_id_from = members.members_id
WHERE mmessages.messages_folder = ? AND messages.join_members_id = ? AND messages.messages_status = ?
GROUP BY NULL',
array('inbox', $members_id, 'unread')
);
$total_unread = $total_unread ? $total_unread : 0;
//------------------------------------------------------------------------------
//-- Update Member Spendable Points, Read Messages and Friend Requests every 30
//-- secs
//------------------------------------------------------------------------------
if($_SESSION['user_id'] and (empty($_SESSION['activity_ping']) or (strtotime('NOW') - $_SESSION['activity_ping'] > 30)))
{
$db = mysqli_db::init();
$total_unread = $db->fetch_singlet('
SELECT COUNT(DISTINCT messages.messages_id) AS total
FROM messages
INNER JOIN members ON messages.join_members_id_from = members.members_id
WHERE mmessages.messages_folder = ? AND messages.join_members_id = ? AND messages.messages_status = ?
GROUP BY NULL',
array('inbox', $members_id, 'unread')
);
$total_unread = $total_unread ? $total_unread : 0;
$_SESSION['activity_ping'] = strtotime('NOW');
}
The drawback of the activity ping is you don't know right away, and there is still a waste on SQL calls to know if they user has a new message. So if you really think about the core issue, its not that we don't know when they get a new message, its we don't know how to tell the member they have a new message when we record it. We can get around them by off-loading the user's session.
So now there is a problem of not knowing the user's session, but we have their ID. So I altered the login to save the member's session id into the database. Now when we save the new message we just load the receiver's session and update their unread message count.
What I did was when every a new message is sent, its updated by piggy backing off the sender's session by loading the receiver's session and update their “total_unread_messages” session variable and then saving and reverting back to the sender's old session. This gets ride of the need to constantly poll to see if they got a new message. The way I know the receiver's session is by keeping that information in a database when they login. This is the same technique you would use to know when a user last logged in.
XML Database Sample <members>
<members_id>2</members_id>
<members_username>sutabi</members_username>
<members_password>aee408847d35e44e99430f0979c3357b85fe8dbb4535a494301198adbee85f27</members_password>
<members_firstname>Joseph</members_firstname>
<members_lastname>Montanez</members_lastname>
<members_email>xxxxx@gmail.com</members_email>
<members_joindate>2009-07-23</members_joindate>
<members_lastlogin>2009-07-24</members_lastlogin>
<members_lastsession>327eca4db44e0e7d17d9107b2f96645b</members_lastsession>
<members_enabled_yn>0</members_enabled_yn>
</members>
$db = mysqli_db::init();
$db->query('UPDATE members
SET members_lastlogin = NOW(), members_lastsession = ?
WHERE members_id = ?',
array(session_id(), $member['members_id'])
);
//-- Send the message to user
//-- ...
//-- Send copy to self
//-- ...
//-- Get receiver's session id
$db = mysqli_db::init();
$member = $db->query('SELECT members_lastsession FROM members WHERE members_id = ?', array($data['join_members_id_to']));
$receivers_last_session = &$member['members_lastsession'];
//-- Update the receivers session to let them know they have a new
//-- message, if they have logged in today
if(empty($members_lastsession) === false and $member['members_lastlogin'] === date('Y-m-d'))
{
//-- Get member's unread messages
$db = mysqli_db::init();
$total_unread = $db->fetch_singlet('
SELECT COUNT(DISTINCT messages.messages_id) AS total
FROM messages
INNER JOIN members ON messages.join_members_id_from = members.members_id
WHERE mmessages.messages_folder = ? AND messages.join_members_id = ? AND messages.messages_status = ?
GROUP BY NULL',
array('inbox', $members_id, 'unread')
);
$total_unread = $total_unread ? $total_unread : 0;
//-- close sender's sessions
$sender_session_id = session_id();
$sender_session_data = $_SESSION; // save current session to a temp variable.
session_commit(); // save and close so we can open a new session
//-- Load receiver's session
session_id($receiver_session_id);
session_start();
//-- Assign message count to receiver's session
$_SESSION['total_unread_messages'] = $total_unread;
//-- Save session data to receiver's session.
//---- session_commit only works once, so it wont write the session to file,
//---- we have to do it manually. It still closes the session and allows us
//---- to open another session id.
file_put_contents(
sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'sess_' . $receiver_session_id,
session_encode()
);
session_commit();
//-- Load sender's session
session_id($sender_session_id);
session_start();
$_SESSION = $sender_session_data; // reload the old session data.
}
Even though updating the member's session works for after they login you still need to poll at login, to see if they have a new message. Then once more when they read the new message, you re-poll again.Php's Session is file-base, so if you are in a cloud environment, then this method would be useless
« Back to my notebook