Powerful Chat System – Lesson 2

Tutorials

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.

Live Demo
download in package

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   `whenint(11) NOT NULL default '0',
07   `room` int(5) unsigned NOT NULL default '0',
08   `type` tinyint(1) unsigned NOT NULL default '0',
09   PRIMARY KEY (`id`)
10 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Step 2. HTML

This is main (index) page html markup:

templates/main_page.html

01 <!DOCTYPE html>
02 <html lang="en" >
03 <head>
04     <title>Powerful Chat System - Lesson 2</title>
05     <link href="css/main.css" rel="stylesheet" type="text/css" />
06     <script src="http://code.jquery.com/jquery-latest.min.js"></script>
07 </head>
08 <body>
09     <header>
10         <h2>Powerful Chat System - Lesson 2</h2>
11         <a href="https://www.script-tutorials.com/powerful-chat-system-lesson-2/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
12     </header>
13     <div class="container">
14         {form}
15     </div>
16     <div class="container">
17         <h2>Main Chat Block</h2>
18         <div class="chat_messages">
19             {chat}
20         </div>
21         {input}
22     </div>
23 </body>
24 </html>

As you can see – I have changed our second container (which contains our ajax chat).

templates/login_form.html and templates/logout_form.html

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>
3     <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>
7     </div>
8 </form>
9 <script src="js/chat.js"></script>

Step 3. CSS

This file contains updated styles of our chat

css/main.css

001 /* page layout */
002 *{
003     margin:0;
004     padding:0;
005 }
006 body {
007     background-color:#eee;
008     color:#fff;
009     font:14px/1.3 Arial,sans-serif;
010 }
011 header {
012     background-color:#212121;
013     box-shadow: 0 -1px 2px #111111;
014     display:block;
015     height:70px;
016     position:relative;
017     width:100%;
018     z-index:100;
019 }
020 header h2{
021     font-size:22px;
022     font-weight:normal;
023     left:50%;
024     margin-left:-400px;
025     padding:22px 0;
026     position:absolute;
027     width:540px;
028 }
029 header a.stuts,a.stuts:visited{
030     border:none;
031     text-decoration:none;
032     color:#fcfcfc;
033     font-size:14px;
034     left:50%;
035     line-height:31px;
036     margin:23px 0 0 110px;
037     position:absolute;
038     top:0;
039 }
040 header .stuts span {
041     font-size:22px;
042     font-weight:bold;
043     margin-left:5px;
044 }
045 /* main styles */
046 .container {
047     background-color: #222;
048     color: #bbb;
049     margin: 20px auto;
050     overflow: hidden;
051     padding: 20px;
052     position: relative;
053     width: 800px;
054 }
055 .container h2 {
056     color: #fff;
057     margin-bottom: 10px;
058 }
059 .column {
060     float: left;
061     width: 48%;
062 }
063 .column:first-child {
064     margin-right: 4%;
065 }
066 .column > * {
067     color: #ddd;
068     margin-bottom: 10px;
069 }
070 .column h3 {
071     color: #fff;
072 }
073 .login_form input,.login_form label {
074     display: block;
075     margin-bottom: 10px;
076 }
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;
082     border-radius: 5px;
083 }
084 input[type=text], input[type=password] {
085     font-size: 16px;
086     height: 30px;
087     margin-right: 10px;
088     width: 200px;
089 }
090 input[type=submit]{
091     cursor: pointer;
092     font-size: 16px;
093     font-weight: bold;
094     height: 35px;
095     padding: 5px;
096 }
097 /* chat block */
098 .chat_messages {
099     border: 1px solid #888;
100     box-shadow: 0 0 5px #AAA;
101     color: #000;
102     padding: 10px;
103 }
104 .chat_messages h2 {
105     color: #fff;
106 }
107 .chat_messages .message {
108     background-color: #fff;
109     margin: 5px;
110     padding: 5px;
111     -moz-border-radius: 5px;
112     -ms-border-radius: 5px;
113     -o-border-radius: 5px;
114     -webkit-border-radius: 5px;
115     border-radius: 5px;
116 }
117 .chat_messages .message span {
118     color: #444;
119     font-size: 10px;
120     margin-left: 10px;
121 }
122 .chat_submit_form {
123     margin: 10px 0px;
124 }
125 .chat_submit_form div {
126     float: left;
127     width: 49%;
128 }
129 .chat_submit_form .error, .chat_submit_form .success, .chat_submit_form .protect {
130     display: none;
131 }
132 .chat_submit_form .error {
133     color: #f55;
134 }
135 .chat_submit_form .success {
136     color: #5f5;
137 }
138 .chat_submit_form .protect {
139     color: #55f;
140 }

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

01 $(function() {
02     getMessages = function() {
03         $.getJSON('index.php?action=get_last_messages'function(data){
04             if (data.messages) {
05                 $('.chat_messages').html(data.messages);
06             }
07             // get recent chat messages in loop
08             setTimeout(function(){
09                getMessages();
10             }, 5000);
11         });
12     }
13     getMessages();
14     $('.chat_submit_form').submit(function() {
15         $.post('index.php', { message: $('.chat_submit_form input[name=message]').val() },
16             function(data){
17                 if (data.result == 1) {
18                     $('.chat_submit_form .success').fadeIn('slow'function () {
19                         $(this).delay(1000).fadeOut('slow');
20                     });
21                 else if (data.result == 2) {
22                     $('.chat_submit_form .protect').fadeIn('slow'function () {
23                         $(this).delay(1000).fadeOut('slow');
24                     });
25                 else {
26                     $('.chat_submit_form .error').fadeIn('slow'function () {
27                         $(this).delay(1000).fadeOut('slow');
28                     });
29                 }
30             }
31         );
32         return false;
33     });
34 });

Step 5. PHP

Now, lets review php sources:

index.php

01 <?php
02 // set error reporting level
03 if (version_compare(phpversion(), '5.3.0''>=') == 1)
04   error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
05 else
06   error_reporting(E_ALL & ~E_NOTICE);
07 require_once('classes/Services_JSON.php');
08 require_once('classes/CMySQL.php'); // including service class to work with database
09 require_once('classes/CLogin.php'); // including service class to work with login processing
10 // login system init and generation code
11 $sLoginForm $GLOBALS['CLogin']->getLoginBox();
12 $sChat '<h2>You do not have rights to use chat</h2>';
13 $sInput '';
14 if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) {
15     require_once('classes/CChat.php'); // including service class to work with chat
16     // get last messages
17     $sChat $GLOBALS['MainChat']->getMessages();
18     if ($_GET['action'] == 'get_last_messages') { // regular updating of messages in chat
19         $oJson new Services_JSON();
20         header('Content-type: application/json');
21         echo $oJson->encode(array('messages' => $sChat));
22         exit;
23     }
24     // get input form
25     $sInput $GLOBALS['MainChat']->getInputForm();
26     if ($_POST['message']) { // POST-ing of message
27         $iRes $GLOBALS['MainChat']->acceptMessage();
28         $oJson new Services_JSON();
29         header('Content-type: application/json');
30         echo $oJson->encode(array('result' => $iRes));
31         exit;
32     }
33 }
34 // draw common page
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

01 <?php
02 class CLogin {
03     // constructor
04     function CLogin() {
05         session_start();
06     }
07     // get login box function
08     function getLoginBox() {
09         if (isset($_GET['logout'])) { // logout processing
10             if (isset($_SESSION['member_name']) && isset($_SESSION['member_pass']))
11                 $this->performLogout();
12         }
13         if ($_POST && $_POST['username'] && $_POST['password']) { // login processing
14             if ($this->checkLogin($_POST['username'], $_POST['password'], false)) { // successful login
15                 $this->performLogin($_POST['username'], $_POST['password']);
16                 header( "Location:{$_SERVER['REQUEST_URI']}" );
17                 exit;
18             else // wrong login
19                 return file_get_contents('templates/login_form.html') . '<h2>Username or Password is incorrect</h2>';
20             }
21         else // in case if we already logged (on refresh page):
22             if (isset($_SESSION['member_name']) && $_SESSION['member_name'] && $_SESSION['member_pass']) {
23                 $aReplaces array(
24                     '{name}' => $_SESSION['member_name'],
25                     '{status}' => $_SESSION['member_status'],
26                     '{role}' => $_SESSION['member_role'],
27                 );
28                 return strtr(file_get_contents('templates/logout_form.html'), $aReplaces);
29             }
30             // otherwise - draw login form
31             return file_get_contents('templates/login_form.html');
32         }
33     }
34     // perform login
35     function performLogin($sName$sPass) {
36         $this->performLogout();
37         // make variables safe
38         $sName $GLOBALS['MySQL']->escape($sName);
39         $aProfile $GLOBALS['MySQL']->getRow("SELECT * FROM `cs_profiles` WHERE `name`='{$sName}'");
40         // $sPassEn = $aProfile['password'];
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;
51     }
52     // perform logout
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']);
59     }
60     // check login
61     function checkLogin($sName$sPass$isHash = true) {
62         // make variables safe
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) {
68             if (! $isHash) {
69                 $sSalt $aProfile['salt'];
70                 $sPass = sha1(md5($sPass) . $sSalt);
71             }
72             return ($sPass == $sPassEn);
73         }
74         return false;
75     }
76 }
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

01 <?php
02 class CChat {
03     // constructor
04     function CChat() {}
05     // add to DB message
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 != '') {
11             $sSQL = "
12                 SELECT `id`
13                 FROM `cs_messages`
14                 WHERE `sender` = '{$iPid}' AND UNIX_TIMESTAMP( ) - `when` < 5
15                 LIMIT 1
16             ";
17             $iLastId $GLOBALS['MySQL']->getOne($sSQL);
18             if ($iLastIdreturn 2; // as protection from very often messages
19             $bRes $GLOBALS['MySQL']->res("INSERT INTO `cs_messages` SET `sender` = '{$iPid}', `message` = '{$sMessage}', `when` = UNIX_TIMESTAMP()");
20             return ($bRes) ? 1 : 3;
21         }
22     }
23     // return input text form
24     function getInputForm() {
25         return file_get_contents('templates/chat.html');
26     }
27     // get last 10 messages
28     function getMessages() {
29         $sSQL = "
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
34             LIMIT 10
35         ";
36         $aMessages $GLOBALS['MySQL']->getAll($sSQL);
37         asort($aMessages);
38         // create list of messages
39         $sMessages '';
40         foreach ($aMessages as $i => $aMessage) {
41             $sExStyles $sExJS '';
42             $iDiff = (int)$aMessage['diff'];
43             if ($iDiff < 7) { // less than 7 seconds
44                 $sExStyles 'style="display:none;"';
45                 $sExJS "<script> $('#message_{$aMessage['id']}').fadeIn('slow'); </script>";
46             }
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;
49         }
50         return $sMessages;
51     }
52 }
53 $GLOBALS['MainChat'] = new CChat();

This is our new class for chat processor. For now – it contain only 3 functions: acceptMessage, getInputForm and getMessages.


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!

Rate article