Powerful Chat System – Lesson 6

Powerful Chat System – Lesson 6

Powerful Chat System

Powerful Chat System – Lesson 6

Today we continue a series of articles on the creation of powerful chat system. In our sixth lesson I have added a list of online members (I will show you how you can manage with it), and, I have updated visual design of out chat also. Now, we have few main blocks at the left side, and new sidebar at the right side (with listings of members).

Today I will publish updated sources of our growing project. All project is well structured: system classes is in ‘classes’ folder, all javascript files in ‘js’ folder, stylesheets in ‘css’ folder, all custom avatars in ‘data’ folder, images in ‘images’ folder, template files in ‘templates’ folder.

Live Demo
download in package

Now – download the source files and lets start coding !


Step 1. SQL

I have added one new field into table of profiles for keeping date of last navigation (so we will able to understand if member is online or not). Please execute next SQL:

ALTER TABLE `cs_profiles` ADD `date_nav` datetime NOT NULL default '0000-00-00 00:00:00' AFTER `date_reg`;

Step 2. HTML

I have updated template of our main page. Now it contains new block with online members:

templates/main_page.html

<!DOCTYPE html>
<html lang="en" >
<head>
    <title>Powerful Chat System - Lesson 6</title>
    <link href="css/main.css" rel="stylesheet" type="text/css" />
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
    <header>
        <h2>Powerful Chat System - Lesson 6</h2>
        <a href="http://www.script-tutorials.com/powerful-chat-system-lesson-6/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
    </header>
    <div class="clear"></div>
    <div class="container" id="con1">
        {form}
        {avatar}
    </div>
    <div class="container" id="con2">
        <h2>Main Chat Block</h2>
        <div class="chat_messages">
            {chat}
        </div>
        {input}
    </div>

    <div class="sidebar">
        <div>
            <h2>Online Members Block</h2>
            {online_members}
        </div>
        <div>
            <h2>Last Members</h2>
            {profiles}
        </div>
    </div>
</body>
</html>

I have updated template of profile page too (not it contains right sidebar with lists of members):

templates/profile_page.html

<!DOCTYPE html>
<html lang="en" >
<head>
    <title>Powerful Chat System - Lesson 6</title>
    <link href="css/main.css" rel="stylesheet" type="text/css" />
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script src="js/customizer.js"></script>
    <style>
        .container {
            {custom_styles}
        }
    </style>
</head>
<body>
    <header>
        <h2>Powerful Chat System - Lesson 6</h2>
        <a href="http://www.script-tutorials.com/powerful-chat-system-lesson-6/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
    </header>
    <div class="clear"></div>
    <div class="container">
        <div class="column">
            <h3>Name: {name}</h3>
            <h3>First name: {fname}</h3>
            <h3>Last name: {lname}</h3>
            <h3>About: {about}</h3>
            <h3>Date Reg: {datereg}</h3>
            <h3>Role: {role}</h3>
            <h3>Avatar: <img src="{avatar}" style="vertical-align:middle" /></h3>
        </div>
        <div class="column">
            <p><a href="index.php">Back to chat</a></p>
        </div>
    </div>
    <div class="container" {cust_visible}>
        <h2>You can customize your profile page</h2>
        <div class="column">
            <canvas id="color_canvas" width="370" height="60"></canvas>
        </div>
        <div class="column">
            <div class="customizer_buttons">
                <div id="preview"></div>
            </div>

            <form action="profile.php" method="GET" target="change_color_result">
                <input type="hidden" value="{id}" name="id">
                <input type="hidden" value="color" name="color" id="color">
                <input type="hidden" value="change_color" name="action">
                <input id="submit" type="submit" name="submit" value="Apply">
            </form>
            <iframe class="avatar_iframe" name="change_color_result"></iframe>
        </div>
    </div>

    <div class="sidebar">
        <div>
            <h2>Online Members Block</h2>
            {online_members}
        </div>
        <div>
            <h2>Last Members</h2>
            {profiles}
        </div>
    </div>
</body>
</html>

And, little visual changes in this file also:

templates/logout_form.html

<div class="column">
    <span style="float:right"><a href="index.php?logout">Log Out</a></span>
    <h3>Hello {name}</h3>
    <h3>Your status:</h3>
    <div>{status}</div>
    <h3>Your role:</h3>
    <div>{role}</div>
</div>

Step 3. CSS

A lot of styles was updated, so lets publish the updated version:

css/main.css

/* page layout */
*{
    margin:0;
    padding:0;
}
body {
    background-color:#eee;
    color:#fff;
    font:14px/1.3 Arial,sans-serif;
}
header {
    background-color:#212121;
    box-shadow: 0 -1px 2px #111111;
    display:block;
    height:70px;
    position:relative;
    width:100%;
    z-index:100;
}
header h2{
    float: left;
    font-size:22px;
    font-weight:normal;
    margin-left:10px;
    margin-right:20px;
    padding:22px 0;
}
header a.stuts,a.stuts:visited{
    float: left;
    text-decoration:none;
    color:#fcfcfc;
    font-size:14px;
    height:70px;
    line-height:70px;
}
header .stuts span {
    font-size:22px;
    font-weight:bold;
    margin-left:5px;
}

/* main styles */
a {
    color: #333;
    outline: none;
    text-decoration: none;
}
a:hover,a:active {
    outline: 0;
    text-decoration: none;
}
.container {
    background-color: #F2F4F8;
    border: 1px solid rgba(0, 0, 0, 0.4);
    box-shadow: 2px 0 2px -2px #B2B9C9 inset;
    color: #333333;
    margin: 20px;
    overflow: hidden;
    padding: 20px;
    position: relative;
    width: 400px;
    float:left;
}
#con1.container {
    width: 300px;
}
#con2.container {
    width: 500px;
}
.container h2 {
    margin-bottom: 10px;
}
.column {
}
.column:first-child {
}
.column > * {
    margin-bottom: 10px;
}
.clear {
    clear: both;
    font-size: 1px;
}
.sidebar {
    background-color: #F2F4F8;
    border-left: 1px solid rgba(0, 0, 0, 0.4);
    box-shadow: 2px 0 2px -2px #B2B9C9 inset;
    color: #333333;
    display: block;
    height: 100%;
    padding: 10px;
    position: fixed;
    right: 0;
    top: 0;
    width: 250px;
    z-index: 101;
}
.sidebar > div {
    margin-bottom: 30px;
}

/* tabs section */
.tabs_container {
    margin: 0;
}
.tabs {
    overflow: hidden;
}
.tabs li {
    float: left;
    list-style: none;
}
.tabs li h3:first-child {
    margin-left: 10px
}
.tabs li h3 {
    border: 1px solid #ddd;
    border-bottom-width: 0;
    display: block;
    margin: 0 2px 0 0;
    padding: 6px 10px 4px
}
.tabs li.active h3 {
    background-color: #ccc;
    border: 1px solid #ddd;
    border-bottom-width: 0;

    -moz-border-radius: 4px 4px 0 0;
    -ms-border-radius: 4px 4px 0 0;
    -o-border-radius: 4px 4px 0 0;
    -webkit-border-radius: 4px 4px 0 0;
    border-radius: 4px 4px 0 0;
}
.tabs li h3:hover {
    background-color: #bbb;
    cursor: pointer;
}
.tabs li.active h3:hover {
    background-color: #ccc;
    cursor: normal;
}
.nav_container form {
    background-color: #ccc;
    display: block;
    padding: 15px;
}
.login_form input,.login_form label,
.join_form input,.join_form label {
    display: block;
    margin-bottom: 10px;
}
input[type=text], input[type=password], input[type=submit] {
    -moz-border-radius: 5px;
    -ms-border-radius: 5px;
    -o-border-radius: 5px;
    -webkit-border-radius: 5px;
    border-radius: 5px;
    border-style: groove;
}
input[type=text], input[type=password] {
    border-style: groove;
    font-size: 16px;
    height: 25px;
    margin-right: 10px;
    width: 200px;
}
input[type=submit],
input[type=file]{
    cursor: pointer;
    font-size: 16px;
    font-weight: bold;
    height: 35px;
    padding: 5px;
}
.avatar_iframe {
    border: 2px dashed #000;
    margin-top: 25px;
}

/* chat block */
.chat_messages {
    border: 1px solid #888;
    color: #000;
    padding: 10px;
}
.chat_messages a {
    color: #000;
}
.chat_messages a img {
    margin-right: 10px;
    vertical-align: middle;
    width: 22px;
}
.chat_messages .message {
    background-color: #fff;
    margin: 5px;
    padding: 5px;

    -moz-border-radius: 5px;
    -ms-border-radius: 5px;
    -o-border-radius: 5px;
    -webkit-border-radius: 5px;
    border-radius: 5px;
}
.chat_messages .message span {
    color: #444;
    font-size: 10px;
    margin-left: 10px;
}
.chat_submit_form {
    margin: 10px 0px;
    overflow: hidden;
}
.chat_submit_form .error, .chat_submit_form .success, .chat_submit_form .protect {
    display: none;
}
.chat_submit_form .error {
    color: #f55;
}
.chat_submit_form .success {
    color: #5f5;
}
.chat_submit_form .protect {
    color: #55f;
}

/* profiles */
.profiles {
    overflow: hidden;
}
.profiles a {
    display: block;
}
.profiles div {
    overflow: hidden;
}
.profiles div a {
    color: #333333;
    display: block;
    padding: 2px 22px 2px 10px;
    position: relative;
}
.profiles div a:hover {
    background-color: #E0E4EE;
    box-shadow: 2px 0 2px -2px #B2B9C9 inset;
}

.profiles div img {
    float: left;
    height: 48px;
    margin-right: 8px;
    width: 48px;
}
.profiles div p {
    display: block;
    line-height: 48px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.profiles div img.status_img {
    display: block;
    height: 7px;
    margin-top: -6px;
    position: absolute;
    right: 5px;
    top: 50%;
    width: 7px;
}

/* customize profile page */
.customizer_buttons #preview, .customizer_buttons #pick {
    border: 1px solid #888;
    border-radius: 3px 3px 3px 3px;
    box-shadow: 2px 3px 3px #888;
    height: 40px;
    margin-bottom: 10px;
    width: 80px;
}

Step 4. PHP

Now, lets review php sources. Our index.php file has been updated. Now it contains one interesting thing – the script periodically is updating the time of last navigation for logged in members (each 3 mins). It will let us know if member is online or not.

index.php

<?php

// set error reporting level
if (version_compare(phpversion(), '5.3.0', '>=') == 1)
  error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
else
  error_reporting(E_ALL & ~E_NOTICE);

require_once('classes/Services_JSON.php');
require_once('classes/CMySQL.php'); // including service class to work with database
require_once('classes/CLogin.php'); // including service class to work with login processing
require_once('classes/CProfiles.php'); // including service class to work with profiles

$sErrors = '';
// join processing
if (! isset($_SESSION['member_id']) && $_POST['Join'] == 'Join') {
    $GLOBALS['CProfiles']->registerProfile();
}

// login system init and generation code
$sLoginForm = $GLOBALS['CLogin']->getLoginBox();

$sChat = '<h2>You do not have rights to use chat</h2>';
$sInput = '';
if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) {
    if ($_GET['action'] == 'update_last_nav') { // update last navigate time
        $iPid = (int)$_SESSION['member_id'];
        if ($iPid) {
            $GLOBALS['MySQL']->res("UPDATE `cs_profiles` SET `date_nav` = NOW() WHERE `id` = '{$iPid}'");
        }
        exit;
    }

    require_once('classes/CChat.php'); // including service class to work with chat

    // get last messages
    $sChat = $GLOBALS['MainChat']->getMessages();
    if ($_GET['action'] == 'get_last_messages') { // regular updating of messages in chat
        $oJson = new Services_JSON();
        header('Content-type: application/json');
        echo $oJson->encode(array('messages' => $sChat));
        exit;
    }

    // add avatar
    if ($_POST['action'] == 'add_avatar') {
        $iAvRes = $GLOBALS['CProfiles']->addAvatar();
        header('Content-Type: text/html; charset=utf-8');
        echo ($iAvRes == 1) ? '<h2 style="text-align:center">New avatar has been accepted, refresh main window to see it</h2>' : '';
        exit;
    }

    // get input form
    $sInput = $GLOBALS['MainChat']->getInputForm();

    if ($_POST['message']) { // POST-ing of message
        $iRes = $GLOBALS['MainChat']->acceptMessage();

        $oJson = new Services_JSON();
        header('Content-type: application/json');
        echo $oJson->encode(array('result' => $iRes));
        exit;
    }
}

// get profiles lists
$sProfiles = $GLOBALS['CProfiles']->getProfilesBlock();
$sOnlineMembers = $GLOBALS['CProfiles']->getProfilesBlock(10, true);

// get profile avatar
$sAvatar = $GLOBALS['CProfiles']->getProfileAvatarBlock();

// draw common page
$aKeys = array(
    '{form}' => $sLoginForm . $sErrors,
    '{chat}' => $sChat,
    '{input}' => $sInput,
    '{profiles}' => $sProfiles,
    '{online_members}' => $sOnlineMembers,
    '{avatar}' => $sAvatar
);
echo strtr(file_get_contents('templates/main_page.html'), $aKeys);

Our next updated file is profile view file (where I have added code to display sidebar members):

profile.php

<?php

// set error reporting level
if (version_compare(phpversion(), '5.3.0', '>=') == 1)
  error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
else
  error_reporting(E_ALL & ~E_NOTICE);

require_once('classes/CMySQL.php');
require_once('classes/CLogin.php');
require_once('classes/CProfiles.php');

$iPid = (int)$_GET['id'];

if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) {
    if ($_GET['action'] == 'change_color') {
        $iRes = $GLOBALS['CProfiles']->changeColor($_GET['color']);
        header('Content-Type: text/html; charset=utf-8');
        echo ($iRes == 1) ? '<h2 style="text-align:center">New color has been accepted, refresh main window to see it</h2>' : '';
        exit;
    }
}

$aInfo = $GLOBALS['CProfiles']->getProfileInfo($iPid);

$sName = $aInfo['name'];
$sFName = $aInfo['first_name'];
$sLName = $aInfo['last_name'];
$sAbout = $aInfo['about'];
$sDate = $aInfo['date_reg'];
$sRole = $GLOBALS['CProfiles']->getRoleName($aInfo['role']);
$sAvatar = $GLOBALS['CProfiles']->getProfileAvatar($iPid);
$sCustomBG = ($aInfo['color']) ? 'background-color:#'.$aInfo['color'] : '';

// get profiles lists
$sProfiles = $GLOBALS['CProfiles']->getProfilesBlock();
$sOnlineMembers = $GLOBALS['CProfiles']->getProfilesBlock(10, true);

// draw common page
$aKeys = array(
    '{id}' => $iPid,
    '{name}' => $sName,
    '{fname}' => $sFName,
    '{lname}' => $sLName,
    '{about}' => $sAbout,
    '{datereg}' => $sDate,
    '{role}' => $sRole,
    '{avatar}' => $sAvatar,
    '{custom_styles}' => $sCustomBG,
    '{cust_visible}' => ($_SESSION['member_id'] == $iPid) ? '' : 'style="display:none"',
    '{profiles}' => $sProfiles,
    '{online_members}' => $sOnlineMembers,
);
echo strtr(file_get_contents('templates/profile_page.html'), $aKeys);

This is our next updated file:

classes/CProfiles.php

<?php

define('PROFILE_TIMEOUT', 5); // 5 mins

// Profiles class
class CProfiles {

    // constructor
    function CProfiles() {
    }

    // profile registration
    function registerProfile() {
        $sUsername = $GLOBALS['MySQL']->escape($_POST['username']);
        $sFirstname = $GLOBALS['MySQL']->escape($_POST['firstname']);
        $sLastname = $GLOBALS['MySQL']->escape($_POST['lastname']);
        $sEmail = $GLOBALS['MySQL']->escape($_POST['email']);
        $sPassword = $GLOBALS['MySQL']->escape($_POST['password']);

        if ($sUsername && $sEmail && $sPassword) {
            // check if already exist
            $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `cs_profiles` WHERE `email`='{$sEmail}'");
            if ($aProfile['id'] > 0) {
                $sErrors = '<h2>Another profile with same email already exist</h2>';
            } else {
                // generate Salt and Cached password
                $sSalt = $this->getRandCode();
                $sPass = sha1(md5($sPassword) . $sSalt);

                // add new member into database
                $sSQL = "
                    INSERT INTO `cs_profiles` SET 
                    `name` = '{$sUsername}',
                    `first_name` = '{$sFirstname}',
                    `last_name` = '{$sLastname}',
                    `email` = '{$sEmail}',
                    `password` = '{$sPass}',
                    `salt` = '{$sSalt}',
                    `status` = 'active',
                    `role` = '1',
                    `date_reg` = NOW();
                ";
                $GLOBALS['MySQL']->res($sSQL);

                // autologin
                $GLOBALS['CLogin']->performLogin($sUsername, $sPassword);
            }
        }
    }

    // get random code (for salt)
    function getRandCode($iLen = 8) {
        $sRes = '';

        $sChars = "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
        for ($i = 0; $i < $iLen; $i++) {
            $z = rand(0, strlen($sChars) -1);
            $sRes .= $sChars[$z];
        }
        return $sRes;
    }

    // get profiles block
    function getProfilesBlock($iLim = 10, $bOnlineOnly = false) {
        $iPLimit = PROFILE_TIMEOUT;
        $sOnlineSQL = ($bOnlineOnly) ? 'AND (`date_nav` > SUBDATE(NOW(), INTERVAL ' . $iPLimit . ' MINUTE))' : '';
        $sSQL = "
            SELECT `cs_profiles`.*,
            if (`date_nav` > SUBDATE(NOW(), INTERVAL {$iPLimit} MINUTE ), 1, 0) AS `is_online`
            FROM `cs_profiles`
            WHERE `status` = 'active'
            {$sOnlineSQL}
            ORDER BY `date_reg` DESC
            LIMIT {$iLim} 
        ";
        $aProfiles = $GLOBALS['MySQL']->getAll($sSQL);

        // create list of messages
        $sCode = '';
        foreach ($aProfiles as $i => $aProfile) {
            $sName = ($aProfile['first_name'] && $aProfile['last_name']) ? $aProfile['first_name'] . ' ' . $aProfile['last_name'] : $aProfile['name'];
            $sSName = (strlen($sName) > 32) ? mb_substr($sName, 0, 28) . '...' : $sName;
            $iPid = $aProfile['id'];
            $sAvatar = $this->getProfileAvatar($iPid);

            $sOnline = ($aProfile['is_online'] == 1) ? '<img alt="" src="images/online.png" class="status_img" />' : '';
            $sCode .= '<div id="'.$iPid.'" title="'.$sName.'"><a href="profile.php?id='.$iPid.'"><img src="'.$sAvatar.'" alt="'.$sName.'"><p>'.$sSName.'</p>'.$sOnline.'</a></div>';
        }

        $sClass = ($bOnlineOnly) ? 'profiles online_profiles' : 'profiles';
        return '<div class="'.$sClass.'">' . $sCode . '</div>';
    }

    // get profile info
    function getProfileInfo($i) {
        $sSQL = "
            SELECT * 
            FROM `cs_profiles`
            WHERE `id` = '{$i}'
        ";
        $aInfos = $GLOBALS['MySQL']->getAll($sSQL);
        return $aInfos[0];
    }

    // get role name
    function getRoleName($i) {
        $sRet = 'Ordinary member';
        switch ($i) {
            case 4:
                $sRet = 'Moderator';
                break;
            case 5:
                $sRet = 'Administrator';
                break;
        }
        return $sRet;
    }

    // get profile avatar block
    function getProfileAvatarBlock() {
        if ($_SESSION['member_id']) {
            $aInfo = $this->getProfileInfo((int)$_SESSION['member_id']);
            if (is_array($aInfo) && count($aInfo)) {
                $sName = ($aInfo['first_name'] && $aInfo['last_name']) ? $aInfo['first_name'] . ' ' . $aInfo['last_name'] : $aInfo['name'];

                $aKeys = array(
                    '{id}' => $aInfo['id'],
                    '{image}' => $this->getProfileAvatar($aInfo['id']),
                    '{name}' => $sName
                );
                return strtr(file_get_contents('templates/avatar.html'), $aKeys);
            }
        }
    }

    function getProfileAvatar($i) {
        $sPath = 'data/' . $i . '.jpg';
        return (file_exists($sPath)) ? $sPath : 'images/member.png';
    }

    // add avatar (upload image)
    function addAvatar() {
        $iPid = (int)$_SESSION['member_id'];
        if ($iPid) {
            $sFileTmpName = $_FILES['avatar']['tmp_name'];
            $sDstFilename = 'data/' . $iPid . '.jpg';

            if (file_exists($sFileTmpName) && filesize($sFileTmpName) > 0) {
                $aSize = getimagesize($sFileTmpName);
                if (! $aSize) {
                    @unlink($sFileTmpName);
                    return;
                }

                $bGDInstalled = extension_loaded('gd');

                // resize if GD is installed
                if (! $bGDInstalled)
                    return;

                $iWidth = $iHeight = 48; // width and height for avatar image
                define('IMAGE_TYPE_GIF', 1);
                define('IMAGE_TYPE_JPG', 2);
                define('IMAGE_TYPE_PNG', 3);

                $gdInfoArray = gd_info();
                switch($aSize[2]) {
                    case IMAGE_TYPE_GIF:
                        if (! $gdInfoArray['GIF Read Support'] || ! $gdInfoArray['GIF Create Support'])
                            return;
                        $vSrcImage = @imagecreatefromgif($sFileTmpName);
                        break;
                    case IMAGE_TYPE_JPG:
                        if (! $gdInfoArray['JPG Support'] && ! $gdInfoArray['JPEG Support'])
                            return;
                        $vSrcImage = @imagecreatefromjpeg($sFileTmpName);
                        break;
                    case IMAGE_TYPE_PNG:
                        if (! $gdInfoArray['PNG Support'])
                            return;
                        $vSrcImage = @imagecreatefrompng($sFileTmpName);
                        break;
                    default:
                        return;
                }
                if (! $vSrcImage)
                    return;

                // calculate destination rate and sizes
                $fSrcRate = (float)($aSize[0] / $aSize[1]);
                $fDstRate = (float)($iWidth / $iHeight);
                $fResizeRate = ($fSrcRate > $fDstRate) ? (float)($iWidth / $aSize[0]) : (float)($iHeight / $aSize[1]);
                $iDstWidth = (int)($fResizeRate * $aSize[0]);
                $iDstHeight = (int)($fResizeRate * $aSize[1]);

                if (function_exists('imagecreatetruecolor') && $aSize[2] != IMAGE_TYPE_GIF) {
                    // resize if need (if size is larger than needed)
                    if ($aSize[0] > $iWidth || $aSize[1] > $iHeight) {
                        $vDstImage = imagecreatetruecolor($iDstWidth, $iDstHeight);
                        $vConvRes = imagecopyresampled($vDstImage, $vSrcImage, 0, 0, 0, 0, $iDstWidth, $iDstHeight, $aSize[0], $aSize[1]);
                    } else {
                        $vDstImage = $vSrcImage;
                        $vConvRes = true;
                    }
                } else { // for old GD versions and for GIF images
                    if ($aSize[0] > $iWidth || $aSize[1] > $iHeight) {
                        $vDstImage = imagecreate( $iDstWidth, $iDstHeight );
                        $vConvRes = imagecopyresized($vDstImage, $vSrcImage, 0, 0, 0, 0, $iDstWidth, $iDstHeight, $aSize[0], $aSize[1]);
                    } else {
                        $vDstImage = $vSrcImage;
                        $vConvRes = true;
                    }
                }

                if (! $vConvRes)
                    return;

                $bRes = imagejpeg($vDstImage, $sDstFilename);

                // memory cleanup
                if ($vDstImage != $vSrcImage) {
                    imagedestroy($vSrcImage);
                    imagedestroy($vDstImage);
                } else {
                    imagedestroy($vSrcImage);
                }
                return ($bRes && file_exists($sDstFilename)) ? 1 : '';
            }
        }
    }

    function changeColor($sColor = '') {
        $iPid = (int)$_SESSION['member_id'];
        $sColor = $GLOBALS['MySQL']->escape($sColor);
        if ($iPid && $sColor) {
            if (strlen($sColor) == 4) {
                $sColor = '00' . $sColor;
            }
            $sSQL = "
                UPDATE `cs_profiles` SET 
                `color` = '{$sColor}'
                WHERE `id` = '{$iPid}'
            ";
            $GLOBALS['MySQL']->res($sSQL);
            return 1;
        }
        return;
    }
}

$GLOBALS['CProfiles'] = new CProfiles();

I have updated function getProfilesBlock here. Now it can display online members.

Step 5. Javascript

js/chat.js

I have added a periodic function (for periodic updates of our users):

    updateLastNav = function() {
        $.getJSON('index.php?action=update_last_nav', function() {

            // refresh last nav time
            setTimeout(function(){
               updateLastNav();
            }, 180000); // 3 mins
        });
    }
    updateLastNav();

Live Demo
download in archive

Conclusion

I hope that our new series of articles of chat system creation is useful and interesting for you. If you want to share your ideas, or you noticed any weakness – don’t hesitate to contact us. Good luck and welcome back!

SIMILAR ARTICLES

Sliding single-level menu

0 71
Design Patterns in PHP

0 3191

4 COMMENTS

  1. Perfect!!!
    Please, are you can create in this chat function send message user? I mean private message.
    Thanks for tutorial and script! :)

  2. What need insert in here?

    mysql_query(“SET names UTF8″);

    I mean what insert instead of “SET names UTF8″

    Thanks in advance

    • This query gives us possibility to use different languages in chat (not only english letters). Do, just keep this query.

Leave a Reply