Powerful Chat System – Lesson 8

Powerful Chat System – Lesson 8

6 51740
Powerful Chat System

Powerful Chat System – Lesson 8

Today we continue a series of articles on the creation of powerful chat system. In our eighth lesson I added several features: I gave right to block (and unblock) members for admins and moderators (now, they can perform normal moderation – they can ban members), and I added rates to our members. Now, every active member can put his vote for another 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 added one new table into database ‘cs_profiles_vote_track’. This table keeps records voting (track). Please execute next SQL:

CREATE TABLE `cs_profiles_vote_track` (
  `pid` int(11) unsigned NOT NULL default '0',
  `ip` varchar(20) default NULL,
  `date` datetime default NULL,
  KEY `uip` (`ip`,`pid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Step 2. HTML

I updated template of our profile page. Now it contains extra button (block feature) and rate block:

templates/profile_page.html


<html lang="en" >
<head>
    <title>Powerful Chat System - Lesson 8</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 8</h2>
        <a href="https://www.script-tutorials.com/powerful-chat-system-lesson-8/" 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>
                {actions}
            </p>
        </div>
    </div>
    {rate}
    <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>
    <div class="priv_dock_wrap"></div>
    {priv_js}
</body>
</html>

And, we have one new template for rate block:

templates/vote.html

<link href="css/vote.css" rel="stylesheet" type="text/css" />
<script src="js/vote.js"></script>
<div class="clear"></div>
<div class="container">
    <div class="column">
        <div class="votes_main">
            <div class="votes_gray" style="width:{width}px;">
                <div class="votes_buttons" id="{pid}" cnt="{rate_cnt}" val="{rate_avg}">
                    {votes}
                </div>
                <div class="votes_active" style="width:{act_width}px;"></div>
            </div>
            <span><b>{rate_cnt}</b> votes</span>
        </div>
    </div>
</div>

Step 3. CSS

I added new css file to keep styles of our vote element:

css/vote.css

.votes_main {
    margin: 10px auto;
    overflow: hidden;
    width: 450px;
}
.votes_gray {
    background-image: url("../images/star_gray.png");
    float: left;
    height: 64px;
    position: relative;
}
.votes_active {
    background-image: url("../images/star.png");
    height: 64px;
    left: 0;
    position: absolute;
    top: 0;
    z-index: 1;
}
.votes_buttons {
    left: 0;
    position: absolute;
    top: 0;
    z-index: 2;
}
.votes_button {
    border: medium none;
    height: 64px;
    margin: 0;
    padding: 0;
    width: 64px;
}
.votes_main span {
    color: #333333;
    display: block;
    float: left;
    font-weight: bold;
    font-size: 18px;
    line-height: 64px;
    margin-left: 10px;
}

Step 4. PHP

Profile page file was updated, I added only few lines at the bottom (into array), it isn’t necessary to publish whole file, but I will give you updated array:

profile.php

// 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,
    '{priv_js}' => $sPrivChatJs,
    '{actions}' => $GLOBALS['CProfiles']->getBlockMemberAction($iPid),
    '{rate}' => $GLOBALS['CProfiles']->getBlockRate($iPid),
);

This is our next updated file. There are three new functions (you can add them at the bottom of our class:

classes/CProfiles.php

// get block member action button
function getBlockMemberAction($iPid) {
    if ($_SESSION['member_id'] != $iPid && $_SESSION['member_status'] == 'active' && in_array($_SESSION['member_role'], array(4, 5))) {
        $aMyInfo = $this->getProfileInfo($_SESSION['member_id']);
        $aInfo = $this->getProfileInfo($iPid);
        if ($aMyInfo['role'] > $aInfo['role']) {
            $sStatus = $aInfo['status'];
            $sDescDesc = ($sStatus == 'active') ? 'Block this member' : 'Unblock this member';
            return '<font style="float:right"><button id="block" pid="'.$iPid.'">'.$sDescDesc.'</button></font><script src="js/admin_utils.js"></script>';
        }
    }
}
// block member
function blockMember($iPid) {
    if ($iPid) {
        $aInfo = $this->getProfileInfo($iPid);
        $sStatus = $aInfo['status'];
        $sUpStatus = ($sStatus == 'active') ? 'passive' : 'active';
        $sSQL = "
            UPDATE `cs_profiles` SET
            `status` = '{$sUpStatus}'
            WHERE `id` = '{$iPid}'
        ";
        $GLOBALS['MySQL']->res($sSQL);
        return ($sStatus == 'active') ? 2 : 1;
    }
    return;
}
// get block member action button
function getBlockRate($iPid) {
    if ($_SESSION['member_id'] != $iPid && $_SESSION['member_status'] == 'active') {
        // $aMyInfo = $this->getProfileInfo($_SESSION['member_id']);
        $aInfo = $this->getProfileInfo($iPid);
        // vote element
        $iIconSize = 64;
        $iMax = 5;
        $iRate = $aInfo['rate'];
        $iRateCnt = $aInfo['rate_count'];
        $fRateAvg = ($iRate && $iRateCnt) ? $iRate / $iRateCnt : 0;
        $iWidth = $iIconSize*$iMax;
        $iActiveWidth = round($fRateAvg*($iMax ? $iWidth/$iMax : 0));
        $sVot = '';
        for ($i=1 ; $i<=$iMax ; $i++) {
            $sVot .= '<a href="#" id="'.$i.'"><img class="votes_button" src="images/empty.gif" alt="" /></a>';
        }
        $aKeys = array(
            '{pid}' => $iPid,
            '{width}' => $iWidth,
            '{rate_cnt}' => $iRateCnt,
            '{rate_avg}' => $fRateAvg,
            '{votes}' => $sVot,
            '{act_width}' => $iActiveWidth,
        );
        return strtr(file_get_contents('templates/vote.html'), $aKeys);
    }
}

First one function getBlockMemberAction returns one little button for profile page. Clicking at this page will force block / unblock members. This function available only for moderators and admins. And, moderator can’t block admin, only admin can block moderator. Second one function blockMember updates profile status (block). And, last one – getBlockRate returns block with rate object (stars), where we can vote for members.

In order to perform different actions, I added one new PHP file:

actions.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');
// for logged-in members only
if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active') {
    if (in_array($_SESSION['member_role'], array(4, 5))) { // for moderators and admins only
        if ($_POST['action'] == 'block') { // Block action
            $iRes = $GLOBALS['CProfiles']->blockMember((int)$_POST['pid']);
            header('Content-Type: text/html; charset=utf-8');
            echo $iRes;
            exit;
        }
    }
    if ($_POST['action'] == 'put_vote') { // Put vote action
        $iPid = (int)$_POST['id'];
        $iVote = (int)$_POST['vote'];
        $sIp = getVisitorIP();
        // we can vote once per week (protection)
        $iOldId = $GLOBALS['MySQL']->getOne("SELECT `pid` FROM `cs_profiles_vote_track` WHERE `pid` = '{$iPid}' AND `ip` = '{$sIp}' AND (`date` >= NOW() - INTERVAL 7 DAY) LIMIT 1");
        if (! $iOldId) {
            $GLOBALS['MySQL']->res("INSERT INTO `cs_profiles_vote_track` SET `pid` = '{$iPid}', `ip` = '{$sIp}', `date` = NOW()");
            $GLOBALS['MySQL']->res("UPDATE `cs_profiles` SET `rate` = `rate` + {$iVote}, `rate_count` = `rate_count` + 1 WHERE `id` = '{$iPid}'");
            header('Content-Type: text/html; charset=utf-8');
            echo 1;
            exit;
        }
    }
}
function getVisitorIP() {
    $ip = "0.0.0.0";
    if( ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) && ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } elseif( ( isset( $_SERVER['HTTP_CLIENT_IP'])) && (!empty($_SERVER['HTTP_CLIENT_IP'] ) ) ) {
        $ip = explode(".",$_SERVER['HTTP_CLIENT_IP']);
        $ip = $ip[3].".".$ip[2].".".$ip[1].".".$ip[0];
    } elseif((!isset( $_SERVER['HTTP_X_FORWARDED_FOR'])) || (empty($_SERVER['HTTP_X_FORWARDED_FOR']))) {
        if ((!isset( $_SERVER['HTTP_CLIENT_IP'])) && (empty($_SERVER['HTTP_CLIENT_IP']))) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
    }
    return $ip;
}

Since today, I will use this file to perform different hidden actions. Now, I use this file to perform member blocking and to accept votes for members.

Step 5. Javascript

I added new JS file which will perform different admin’s service methods. First of them is blocking of members

js/admin_utils.js

$(function() {
    // block member
    $('#block').click(function(event) {
        var oBtn = $(this);
        $.post('actions.php', { pid: oBtn.attr('pid'), action: 'block' },
            function(data){
                if (data != undefined) {
                    oBtn[0].innerHTML = (data == 2) ? 'Unblock this member' : 'Block this member';
                }
            }
        );
    });
});

Another one JS file to work with rate object

js/vote.js

$(function(){
    var width = 0;
    $('.votes_buttons a').hover(
        function () {
            width = $(this).attr('id') * 64;
            $('.votes_active').width(width + 'px');
        },
        function () {
            width = $(this).parent().attr('val') * 64;
            $('.votes_active').width(width + 'px');
        }
    );
    $('.votes_buttons a').click(function () {
        var idVal = $(this).parent().attr('id');
        var iCnt = $(this).parent().attr('cnt');
        var voteVal = $(this).attr('id');
        var iSelWidth = voteVal * 64;
        $.post('actions.php', { id: idVal, vote: voteVal, action: 'put_vote' },
            function(data){
                if (data == 1) {
                    width = iSelWidth;
                    $('.votes_active').width(iSelWidth + 'px');
                    iCnt = parseInt(iCnt) + 1;
                    $('.votes_main span b').text(iCnt);
                    $('.votes_buttons').attr('val', voteVal);
                }
            }
        );
    });
});

Live Demo
download in archive

Conclusion

I hope that our new series of articles of chat system creation is very 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

Understanding Closures

0 11320

6 COMMENTS

    • Hello issaka,
      it doesn’t matter if recipient is online or offline, you can send him PM message anytime. Just click ‘send PM’ icon near his thumb at right column

  1. in the future can you show us how to create voice over ip and video chat thank this is a great tutorial.

  2. Friend Josh please Reply my In this email
    Please Help Me i dont know How to install This chat
    this is my website i want to instal this chat please reply me now How To instal or reply me and i send you the info Website
    FTP MYSQL….. please help me Friend Please

    • Hello, basically, you have to:
      1) unpack our demo package on your side (localhost)
      2) also – run provided SQL in your phpMyAdmin
      3) run it on your localhost

Leave a Reply to admin Cancel reply