Powerful Chat System – Lesson 3

Powerful Chat System – Lesson 3

0 10715
Powerful Chat System

Powerful Chat System – Lesson 3

Today we continue a series of articles on the creation of powerful chat system. Our third lesson will contain next elements: join form (with html5 validation). A long ago, I have already made similar validation. So you can refresh your memories if you like.

Today I will publish updated sources of our growing project (several files was modified, plus I expanded structure of database slightly). All project is well structured: system classes is in ‘classes’ folder, stylesheets in ‘css’ folder, template files in ‘templates’ folder, and – new folder ‘js’ for javascript files.

Live Demo
download in package

Now – download the source files and lets start coding !


Step 1. SQL

I have added new field into table of profiles where we will store its first names. So, please execute next SQL:

ALTER TABLE `cs_profiles` ADD `first_name` varchar(255) NOT NULL default '' AFTER `name`;

Step 2. HTML

I have updated template with login form. As you can see – I have expanded this markup and added join form here:

templates/logout_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">
<div class="tabs_container">
<ul class="tabs">
<li class="active"><h3>Log In</h3></li>
<li><h3>Join</h3></li>
</ul>
</div>
<div class="nav_container">
<form class="login_form" action="index.php" method="post" id="1">
<label>Username:</label><input type="text" name="username">
<label>Password:</label><input type="password" name="password">
<input type="submit" name="Login" value="Login">
</form>
<form class="join_form" action="index.php" method="post" id="2" style="display: none;">
<label>Full name:</label>
<input type="text" id="username" name="username" placeholder="Your name" maxlength="128" title="Your name" required>
<label>First name:</label>
<input type="text" id="firstname" name="firstname" placeholder="Your first name" maxlength="128" title="Your first name">
<label>Last name:</label>
<input type="text" id="lastname" name="lastname" placeholder="Your last name" maxlength="128" title="Your last name">
<label>Email:</label>
<input type="text" id="email" name="email" placeholder="Your email" maxlength="128" title="Format: *@gmail.com" pattern=".*@gmail\.com" required>
<label>Password:</label>
<input type="text" id="password" name="password" maxlength="128" title="Password" required>
<label>Repeat Password:</label>
<input type="text" id="password" name="password" maxlength="128" title="Repeat password" required oninput="checkpass(this)">
<input type="submit" name="Join" value="Join">
</form>
</div>
</div>
<script>
$(document).ready(function(){
$('.tabs li h3').click(function () {
$('.tabs li').removeClass('active');
$(this).parent().addClass('active');
$('.nav_container form').hide();
var index = $('.tabs li h3').index(this);
$('.nav_container form').eq(index).show();
return false;
});
});
function checkpass(input) {
if (input.value != document.getElementById('password').value) {
input.setCustomValidity('Password must match.');
} else {
input.setCustomValidity('');
}
}
</script>

Please pay attention to HTML structure of join form, it contain several new attributes for html5 validation: placeholder, required and pattern. This is pretty interesting.

Step 3. CSS

This file has updated too

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;
}
.container h2 {
color: #fff;
margin-bottom: 10px;
}
.column {
float: left;
width: 48%;
}
.column:first-child {
margin-right: 4%;
}
.column > * {
color: #ddd;
margin-bottom: 10px;
}
/* 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: #555;
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: #666;
cursor: pointer;
}
.tabs li.active h3:hover {
background-color: #555;
cursor: normal;
}
.nav_container form {
background-color: #555;
display: block;
padding: 15px;
}
.column h3 {
color: #fff;
}
.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;
}
input[type=text], input[type=password] {
font-size: 16px;
height: 25px;
margin-right: 10px;
width: 200px;
}
input[type=submit]{
cursor: pointer;
font-size: 16px;
font-weight: bold;
height: 35px;
padding: 5px;
}
/* chat block */
.chat_messages {
border: 1px solid #888;
box-shadow: 0 0 5px #AAA;
color: #000;
padding: 10px;
}
.chat_messages h2 {
color: #fff;
}
.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;
}
.chat_submit_form div {
float: left;
width: 49%;
}
.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;
}

Step 4. PHP

Now, lets review php sources. Our index.php file has updated. I have added here join processing functional. Before actual joining, we have to check if someone else was joined with same email (this field should be unique of course)

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
$sErrors = '';
// join processing
if (! isset($_SESSION['member_id']) && $_POST['Join'] == 'Join') {
$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 = 'testing'; // TODO - we will add generation of salt in future
$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);
}
}
}
// 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']) {
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;
}
// 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;
}
}
// draw common page
echo strtr(file_get_contents('templates/main_page.html'), array('{form}' => $sLoginForm . $sErrors, '{chat}' => $sChat, '{input}' => $sInput));

As you can see – I have added chat functionality today.

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['Login'] == 'Login' && $_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'];
$iPid = $aProfile['id'];
$sSalt = $aProfile['salt'];
$sStatus = $aProfile['status'];
$sRole = $aProfile['role'];
$sPass = sha1(md5($sPass) . $sSalt);
$_SESSION['member_id'] = $iPid;
$_SESSION['member_name'] = $sName;
$_SESSION['member_pass'] = $sPass;
$_SESSION['member_status'] = $sStatus;
$_SESSION['member_role'] = $sRole;
}
// perform logout
function performLogout() { 
unset($_SESSION['member_id']);
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();

Minor changes were made in this file too. The rest of the functional was not changed. We will continue enhance our chat soon.


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

Bootstrap Forms

0 10
jQuery Mobile Lesson 6

0 5

NO COMMENTS

Leave a Reply