Today we continue a series of articles on the creation of powerful chat system. Our second lesson will contain next elements: smart chat (ajax, with spam filtering – protection from the frequent messages). I have decided to make registration for next lesson. Hope that it is ok for you.
Today I have included next elements: chat processor, plus – slight corrections in our previous sources. 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.
Now – download the source files and lets start coding !
Step 1. SQL
This table has got minor changes. I have changed type of field ‘when’.
01 | CREATE TABLE `cs_messages` ( |
02 | `id` int(11) unsigned NOT NULL auto_increment, |
03 | `sender` int(11) unsigned NOT NULL, |
04 | `recipient` int(11) unsigned NOT NULL default '0', |
05 | `message` VARCHAR(255) NOT NULL, |
06 | `when` int(11) NOT NULL default '0', |
07 | `room` int(5) unsigned NOT NULL default '0', |
08 | `type` tinyint(1) unsigned NOT NULL default '0', |
10 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; |
Step 2. HTML
This is main (index) page html markup:
templates/main_page.html
04 | <title>Powerful Chat System - Lesson 2</title> |
05 | <link href="css/main.css" rel="stylesheet" type="text/css" /> |
10 | <h2>Powerful Chat System - Lesson 2</h2> |
13 | <div class="container"> |
16 | <div class="container"> |
17 | <h2>Main Chat Block</h2> |
18 | <div class="chat_messages"> |
As you can see – I have changed our second container (which contains our ajax chat).
These files haven’t changed since last time. Next one new template – chat form:
templates/chat.html
1 | <form class="chat_submit_form"> |
2 | <div><input type="text" name="message" /><input type="submit" value="Submit" name="Submit" /></div> |
4 | <h3 class="error">Some error occurs during sending message</h3> |
5 | <h3 class="success">Message successfully sent</h3> |
6 | <h3 class="protect">Please wait 5 secs before adding next message</h3> |
9 | <script src="js/chat.js"></script> |
Step 3. CSS
This file contains updated styles of our chat
css/main.css
007 | background-color:#eee; |
009 | font:14px/1.3 Arial,sans-serif; |
012 | background-color:#212121; |
013 | box-shadow: 0 -1px 2px #111111; |
029 | header a.stuts,a.stuts:visited{ |
031 | text-decoration:none; |
036 | margin:23px 0 0 110px; |
047 | background-color: #222; |
063 | .column:first-child { |
073 | .login_form input,.login_form label { |
077 | input[type=text], input[type=password], input[type=submit] { |
078 | -moz-border-radius: 5px; |
079 | -ms-border-radius: 5px; |
080 | -o-border-radius: 5px; |
081 | -webkit-border-radius: 5px; |
084 | input[type=text], input[type=password] { |
099 | border: 1px solid #888; |
100 | box-shadow: 0 0 5px #AAA; |
107 | .chat_messages .message { |
108 | background-color: #fff; |
111 | -moz-border-radius: 5px; |
112 | -ms-border-radius: 5px; |
113 | -o-border-radius: 5px; |
114 | -webkit-border-radius: 5px; |
117 | .chat_messages .message span { |
125 | .chat_submit_form div { |
129 | .chat_submit_form .error, .chat_submit_form .success, .chat_submit_form .protect { |
132 | .chat_submit_form .error { |
135 | .chat_submit_form .success { |
138 | .chat_submit_form .protect { |
Step 4. JS
I have created first JS for our chat. At beginning – it contain one function for regular obtaining messages, and handler of form submitting.
js/chat.js
02 | getMessages = function() { |
03 | $.getJSON('index.php?action=get_last_messages', function(data){ |
05 | $('.chat_messages').html(data.messages); |
08 | setTimeout(function(){ |
14 | $('.chat_submit_form').submit(function() { |
15 | $.post('index.php', { message: $('.chat_submit_form input[name=message]').val() }, |
17 | if (data.result == 1) { |
18 | $('.chat_submit_form .success').fadeIn('slow', function () { |
19 | $(this).delay(1000).fadeOut('slow'); |
21 | } else if (data.result == 2) { |
22 | $('.chat_submit_form .protect').fadeIn('slow', function () { |
23 | $(this).delay(1000).fadeOut('slow'); |
26 | $('.chat_submit_form .error').fadeIn('slow', function () { |
27 | $(this).delay(1000).fadeOut('slow'); |
Step 5. PHP
Now, lets review php sources:
index.php
03 | if (version_compare(phpversion(), '5.3.0', '>=') == 1) |
04 | error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED); |
06 | error_reporting(E_ALL & ~E_NOTICE); |
07 | require_once('classes/Services_JSON.php'); |
08 | require_once('classes/CMySQL.php'); |
09 | require_once('classes/CLogin.php'); |
11 | $sLoginForm = $GLOBALS['CLogin']->getLoginBox(); |
12 | $sChat = '<h2>You do not have rights to use chat</h2>'; |
14 | if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) { |
15 | require_once('classes/CChat.php'); |
17 | $sChat = $GLOBALS['MainChat']->getMessages(); |
18 | if ($_GET['action'] == 'get_last_messages') { |
19 | $oJson = new Services_JSON(); |
20 | header('Content-type: application/json'); |
21 | echo $oJson->encode(array('messages' => $sChat)); |
25 | $sInput = $GLOBALS['MainChat']->getInputForm(); |
26 | if ($_POST['message']) { |
27 | $iRes = $GLOBALS['MainChat']->acceptMessage(); |
28 | $oJson = new Services_JSON(); |
29 | header('Content-type: application/json'); |
30 | echo $oJson->encode(array('result' => $iRes)); |
35 | echo strtr(file_get_contents('templates/main_page.html'), array('{form}' => $sLoginForm, '{chat}' => $sChat, '{input}' => $sInput)); |
As you can see – I have added chat functionality today.
classes/CLogin.php
08 | function getLoginBox() { |
09 | if (isset($_GET['logout'])) { |
10 | if (isset($_SESSION['member_name']) && isset($_SESSION['member_pass'])) |
11 | $this->performLogout(); |
13 | if ($_POST && $_POST['username'] && $_POST['password']) { |
14 | if ($this->checkLogin($_POST['username'], $_POST['password'], false)) { |
15 | $this->performLogin($_POST['username'], $_POST['password']); |
16 | header( "Location:{$_SERVER['REQUEST_URI']}" ); |
19 | return file_get_contents('templates/login_form.html') . '<h2>Username or Password is incorrect</h2>'; |
22 | if (isset($_SESSION['member_name']) && $_SESSION['member_name'] && $_SESSION['member_pass']) { |
24 | '{name}' => $_SESSION['member_name'], |
25 | '{status}' => $_SESSION['member_status'], |
26 | '{role}' => $_SESSION['member_role'], |
28 | return strtr(file_get_contents('templates/logout_form.html'), $aReplaces); |
31 | return file_get_contents('templates/login_form.html'); |
35 | function performLogin($sName, $sPass) { |
36 | $this->performLogout(); |
38 | $sName = $GLOBALS['MySQL']->escape($sName); |
39 | $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `cs_profiles` WHERE `name`='{$sName}'"); |
41 | $iPid = $aProfile['id']; |
42 | $sSalt = $aProfile['salt']; |
43 | $sStatus = $aProfile['status']; |
44 | $sRole = $aProfile['role']; |
45 | $sPass = sha1(md5($sPass) . $sSalt); |
46 | $_SESSION['member_id'] = $iPid; |
47 | $_SESSION['member_name'] = $sName; |
48 | $_SESSION['member_pass'] = $sPass; |
49 | $_SESSION['member_status'] = $sStatus; |
50 | $_SESSION['member_role'] = $sRole; |
53 | function performLogout() { |
54 | unset($_SESSION['member_id']); |
55 | unset($_SESSION['member_name']); |
56 | unset($_SESSION['member_pass']); |
57 | unset($_SESSION['member_status']); |
58 | unset($_SESSION['member_role']); |
61 | function checkLogin($sName, $sPass, $isHash = true) { |
63 | $sName = $GLOBALS['MySQL']->escape($sName); |
64 | $sPass = $GLOBALS['MySQL']->escape($sPass); |
65 | $aProfile = $GLOBALS['MySQL']->getRow("SELECT * FROM `cs_profiles` WHERE `name`='{$sName}'"); |
66 | $sPassEn = $aProfile['password']; |
67 | if ($sName && $sPass && $sPassEn) { |
69 | $sSalt = $aProfile['salt']; |
70 | $sPass = sha1(md5($sPass) . $sSalt); |
72 | return ($sPass == $sPassEn); |
77 | $GLOBALS['CLogin'] = new CLogin(); |
This class is updated too. I have decided to add ‘member_id’ in sessions too. It will useful afterward.
classes/CMySQL.php
This is database service class. Available in package. Pay attention – database settings of our project is in this file.
classes/Services_JSON.php
This is JSON service class. Available in package.
classes/CChat.php
06 | function acceptMessage() { |
07 | $sName = $GLOBALS['MySQL']->escape($_SESSION['member_name']); |
08 | $iPid = (int)$_SESSION['member_id']; |
09 | $sMessage = $GLOBALS['MySQL']->escape($_POST['message']); |
10 | if ($iPid && $sName != '' && $sMessage != '') { |
14 | WHERE `sender` = '{$iPid}' AND UNIX_TIMESTAMP( ) - `when` < 5 |
17 | $iLastId = $GLOBALS['MySQL']->getOne($sSQL); |
18 | if ($iLastId) return 2; |
19 | $bRes = $GLOBALS['MySQL']->res("INSERT INTO `cs_messages` SET `sender` = '{$iPid}', `message` = '{$sMessage}', `when` = UNIX_TIMESTAMP()"); |
20 | return ($bRes) ? 1 : 3; |
24 | function getInputForm() { |
25 | return file_get_contents('templates/chat.html'); |
28 | function getMessages() { |
30 | SELECT `a` . * , `cs_profiles`.`name` , UNIX_TIMESTAMP( ) - `a`.`when` AS 'diff' |
31 | FROM `cs_messages` AS `a` |
32 | INNER JOIN `cs_profiles` ON `cs_profiles`.`id` = `a`.`sender` |
33 | ORDER BY `a`.`id` DESC |
36 | $aMessages = $GLOBALS['MySQL']->getAll($sSQL); |
40 | foreach ($aMessages as $i => $aMessage) { |
41 | $sExStyles = $sExJS = ''; |
42 | $iDiff = (int)$aMessage['diff']; |
44 | $sExStyles = 'style="display:none;"'; |
45 | $sExJS = "<script> $('#message_{$aMessage['id']}').fadeIn('slow'); </script>"; |
47 | $sWhen = date("H:i:s", $aMessage['when']); |
48 | $sMessages .= '<div class="message" id="message_'.$aMessage['id'].'" '.$sExStyles.'><b>' . $aMessage['name'] . ':</b> ' . $aMessage['message'] . '<span>(' . $sWhen . ')</span></div>' . $sExJS; |
53 | $GLOBALS['MainChat'] = new CChat(); |
This is our new class for chat processor. For now – it contain only 3 functions: acceptMessage, getInputForm and getMessages.
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!