• Reading time:9 mins read
Powerful Chat System

Powerful Chat System

Today we begin a series of articles on the creation of powerful chat system. The system will contain next elements: registration, login processing, main chat, profiles with avatars, ranking system (of profiles), private messaging, custom rooms, moderation / administration and possible something else (in future). This will be ajax chat PHP) with storing messages in database (MySQL). Plus we will implement CSS3/HTML5 features in our development process.

Today I have included next elements: initial code (PHP + SQL) with login processor. All project will be well structured: system classes is in ‘classes’ folder, stylesheets in ‘css’ folder, template files in ‘templates’ folder.

Live Demo
download in package

Now – download the source files and lets start coding !


Step 1. SQL

Here is SQL structure of tables for profiles and messages

CREATE TABLE `cs_profiles` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `name` varchar(255) NOT NULL default '',
  `last_name` varchar(255) NOT NULL default '',
  `email` varchar(255) NOT NULL default '',
  `password` varchar(40) NOT NULL default '',
  `salt` varchar(10) NOT NULL default '',
  `status` enum('active','passive') NOT NULL default 'active',
  `role` tinyint(4) unsigned NOT NULL default '1',
  `about` varchar(255) NOT NULL,
  `date_reg` datetime NOT NULL default '0000-00-00 00:00:00',
  `rate` float NOT NULL,
  `rate_count` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

INSERT INTO `cs_profiles` (`name`, `last_name`, `email`, `password`, `salt`, `status`, `role`, `about`, `date_reg`, `rate`, `rate_count`) VALUES
('test user', 'test user last name', 'user@user.com', 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'testing', 'active', 1, 'Few words about test user', '2012-01-14 00:00:00', 0, 0),
('moderator', 'moderator last name', 'moderator@moderator.com', 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'testing', 'active', 4, 'Few words about moderator', '2012-01-14 00:00:00', 0, 0),
('admin', 'admin last name', 'admin@admin.com', 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'testing', 'active', 5, 'Few words about admin', '2012-01-14 00:00:00', 0, 0);

CREATE TABLE `cs_messages` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `sender` int(11) unsigned NOT NULL,
  `recipient` int(11) unsigned NOT NULL default '0',
  `message` VARCHAR(255) NOT NULL,
  `when` TIMESTAMP NOT NULL default CURRENT_TIMESTAMP,
  `room` int(5) unsigned NOT NULL default '0',
  `type` tinyint(1) unsigned NOT NULL default '0',
  PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

I have added 3 profiles in the system. Each of them have different role. I plan to make ordinary members (1), moderators (4), administrators (5). You can use another roles (as example 2 and 3) for any other purposes (paid members?). And, quite forgot – password for all of them is ‘password’. So you can login as ‘test user’ -> ‘password’, ‘moderator’ -> ‘password’ and ‘admin’ -> ‘password’. Registration process will in next article.

Step 2. HTML

This is main (index) page html markup:

templates/main_page.html

<!DOCTYPE html>
<html lang="en" >
<head>
    <title>Powerful Chat System</title>
    <link href="css/main.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <header>
        <h2>Powerful Chat System</h2>
        <a href="https://dev-school.net/powerful-chat-system/" class="stuts">Back to original tutorial on <span>Dev School</span></a>
    </header>
    <div class="container">
        {form}
    </div>
    <div class="container">
        {chat}
    </div>
</body>
</html>

It is easy layout, isn’t it?. Now, next template file for login form:

templates/login_form.html

<div class="column">
    <h3>Powerful Chat System Demonstration</h3>
    <p>Our chat will contain next features: registration, main chat, profiles with avatars, ranking system, private messaging, custom rooms, moderation / administration and possible something else (in future).</p>
</div>
<div class="column">
    <form class="login_form" action="index.php" method="post">
        <h3>Log In</h3>
        <label>Username:</label><input type="text" name="username">
        <label>Password:</label><input type="password" name="password">
        <input type="submit" name="LogIn" value="Login">
    </form>
</div>

Next one template – logout form:

logout_form.html

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

Step 3. CSS

This file contains styles of our page layout

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{
    font-size:22px;
    font-weight:normal;
    left:50%;
    margin-left:-400px;
    padding:22px 0;
    position:absolute;
    width:540px;
}
header a.stuts,a.stuts:visited{
    border:none;
    text-decoration:none;
    color:#fcfcfc;
    font-size:14px;
    left:50%;
    line-height:31px;
    margin:23px 0 0 110px;
    position:absolute;
    top:0;
}
header .stuts span {
    font-size:22px;
    font-weight:bold;
    margin-left:5px;
}

/* main styles */
.container {
    background-color:#222;
    color: #bbb;
    margin: 20px auto;
    overflow: hidden;
    padding:20px;
    position: relative;
    width: 800px;
}
.column {
    float:left;
    width:48%;
}
.column:first-child {
    margin-right:4%;
}
.column > * {
    color:#ddd;
    margin-bottom:10px;
}
.column h3 {
    color:#fff;
}
.login_form input,.login_form label {
    display:block;
    margin-bottom:5px;
}
input[type=text],
input[type=password] {
    width:200px;
}
input[type=submit]{
    height:30px;
    margin-top:10px;
    width:72px;
}

Step 4. PHP

Now, lets review php sources:

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/CMySQL.php'); // including service class to work with database
require_once('classes/CLogin.php'); // including service class to work with login processing

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

$sChat = ($_SESSION['member_name'] && $_SESSION['member_status'] == 'active') ? '<h2>TODO chat</h2>' : '<h2>You have to login before use chat</h2>';

echo strtr(file_get_contents('templates/main_page.html'), array('{form}' => $sLoginForm, '{chat}' => $sChat));

As we need only login processing for today – our index file is pretty small. New functional will appear in further articles. Here is sources of our login processor:

classes/CLogin.php

<?php

class CLogin {

    // constructor
    function CLogin() {
        session_start();
    }

    // get login box function
    function getLoginBox() {
        if (isset($_GET['logout'])) { // logout processing
            if (isset($_SESSION['member_name']) && isset($_SESSION['member_pass']))
                $this->performLogout();
        }

        if ($_POST && $_POST['username'] && $_POST['password']) { // login processing
            if ($this->checkLogin($_POST['username'], $_POST['password'], false)) { // successful login
                $this->performLogin($_POST['username'], $_POST['password']);
                header( "Location:{$_SERVER['REQUEST_URI']}" );
                exit;
            } else { // wrong login
                return file_get_contents('templates/login_form.html') . '<h2>Username or Password is incorrect</h2>';
            }
        } else { // in case if we already logged (on refresh page):
            if (isset($_SESSION['member_name']) && $_SESSION['member_name'] && $_SESSION['member_pass']) {
                $aReplaces = array(
                    '{name}' => $_SESSION['member_name'],
                    '{status}' => $_SESSION['member_status'],
                    '{role}' => $_SESSION['member_role'],
                );
                return strtr(file_get_contents('templates/logout_form.html'), $aReplaces);
            }

            // otherwise - draw login form
            return file_get_contents('templates/login_form.html');
        }
    }

    // perform login
    function performLogin($sName, $sPass) {
        $this->performLogout();

        // make variables safe
        $sName = $GLOBALS['MySQL']->escape($sName);

        $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `cs_profiles` WHERE `name`='{$sName}'");
        // $sPassEn = $aProfile['password'];
        $sSalt = $aProfile['salt'];
        $sStatus = $aProfile['status'];
        $sRole = $aProfile['role'];

        $sPass = sha1(md5($sPass) . $sSalt);

        $_SESSION['member_name'] = $sName;
        $_SESSION['member_pass'] = $sPass;
        $_SESSION['member_status'] = $sStatus;
        $_SESSION['member_role'] = $sRole;
    }

    // perform logout
    function performLogout() { 
        unset($_SESSION['member_name']);
        unset($_SESSION['member_pass']);
        unset($_SESSION['member_status']);
        unset($_SESSION['member_role']);
    }

    // check login
    function checkLogin($sName, $sPass, $isHash = true) {
        // make variables safe
        $sName = $GLOBALS['MySQL']->escape($sName);
        $sPass = $GLOBALS['MySQL']->escape($sPass);

        $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `cs_profiles` WHERE `name`='{$sName}'");
        $sPassEn = $aProfile['password'];

        if ($sName && $sPass && $sPassEn) {
            if (! $isHash) {
                $sSalt = $aProfile['salt'];
                $sPass = sha1(md5($sPass) . $sSalt);
            }
            return ($sPass == $sPassEn);
        }
        return false;
    }
}

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

I hope you still remember our previous article of advanced login system. We will have similar system with using sha1 + md5 encryption. All profiles will kept in database.

classes/CMySQL.php

This is database service class. Available in package. Pay attention – database settings of our project is in this file.


Live Demo
download in archive

Conclusion

I will hope that our new series of articles of chat system creation will be 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!