Сегодня мы продолжим нашу работу над чатом. Наш второй урок будет посвящен следующим элементам: smart-чату (ajax, фильтрация спама – предотвращение отправки множественных сообщений). Регистрацию мы решили отложить до следующего урока. Надеемся, что вы не сильно расстроитесь.
Сегодня мы будем работать над процессором чата, а также внесем некоторые изменения в код, который мы написали в предыдущем уроке. Весь проект у нас аккуратно структурирован: системные классы будут в папке «classes», таблицы стилей в папке «css», файлы шаблона в папке «templates», и сегодня мы добавим новую папку «js» для, как вы уже догадались, файлов javascript.
Пока что скачивайте исходник, и дальше мы можем приступать.
Этап 1 - SQL
В эту таблицу мы внесем незначительные изменения. Мы изменили тип поля «when».
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` int(11) NOT NULL default '0', `room` int(5) unsigned NOT NULL default '0', `type` tinyint(1) unsigned NOT NULL default '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Этап 2 - HTML-код
Здесь у нас html-разметка основной страницы (index):
templates/main_page.html
<!DOCTYPE html> <html lang="en" > <head> <title>Powerful Chat System - Lesson 2</title> <link href="css/main.css" rel="stylesheet" type="text/css" /> <script src="http://code.jquery.com/jquery-latest.min.js"></script> </head> <body> <header> <h2>Powerful Chat System - Lesson 2</h2> <a href="http://www.script-tutorials.com/powerful-chat-system-lesson-2/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a> </header> <div class="container"> {form} </div> <div class="container"> <h2>Main Chat Block</h2> <div class="chat_messages"> {chat} </div> {input} </div> </body> </html>
Как видно, мы изменили второй контейнер (который содержит наш чат на ajax).
templates/login_form.html и templates/logout_form.html
Эти файлы не претерпели изменений. Дальше давайте рассмотрим один новый шаблон – форму нашего чата:
templates/chat.html
<form class="chat_submit_form"> <div><input type="text" name="message" /><input type="submit" value="Submit" name="Submit" /></div> <div> <h3 class="error">Some error occurs during sending message</h3> <h3 class="success">Message successfully sent</h3> <h3 class="protect">Please wait 5 secs before adding next message</h3> </div> </form> <script src="js/chat.js"></script>
Этап 3 - CSS-код
Данный файл содержит обновленные стили нашего чата
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; } .column h3 { color: #fff; } .login_form input,.login_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: 30px; 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; }
Этап 4 - JS
Мы создали первый js-файл для нашего чата. В самом начале он содержит функцию для регулярного обновления сообщений, а также контроллер для формы подтверждения.
js/chat.js
$(function() { getMessages = function() { $.getJSON('index.php?action=get_last_messages', function(data){ if (data.messages) { $('.chat_messages').html(data.messages); }
// get recent chat messages in loop setTimeout(function(){ getMessages(); }, 5000); }); } getMessages();
$('.chat_submit_form').submit(function() { $.post('index.php', { message: $('.chat_submit_form input[name=message]').val() }, function(data){ if (data.result == 1) { $('.chat_submit_form .success').fadeIn('slow', function () { $(this).delay(1000).fadeOut('slow'); }); } else if (data.result == 2) { $('.chat_submit_form .protect').fadeIn('slow', function () { $(this).delay(1000).fadeOut('slow'); }); } else { $('.chat_submit_form .error').fadeIn('slow', function () { $(this).delay(1000).fadeOut('slow'); }); } } ); return false; }); });
Этап 5 - PHP-код
Теперь давайте рассмотрим исходный код PHP:
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
// 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, '{chat}' => $sChat, '{input}' => $sInput));
Как видно, сегодня мы добавили сюда функционал чата.
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']; $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();
Данный класс также был обновлен. Мы решили добавить в сессии и 'member_id'. Позже он будет полезен нам.
classes/CMySQL.php
Это класс работы с базой данных. Он есть в архиве. Обратите внимание, настройки базы данных для нашего проекта находятся в этом файле.
classes/Services_JSON.php
Это класс работы с JSON. Он есть в архиве.
classes/CChat.php
<?php
class CChat {
// constructor function CChat() {}
// add to DB message function acceptMessage() { $sName = $GLOBALS['MySQL']->escape($_SESSION['member_name']); $iPid = (int)$_SESSION['member_id']; $sMessage = $GLOBALS['MySQL']->escape($_POST['message']);
if ($iPid && $sName != '' && $sMessage != '') { $sSQL = " SELECT `id` FROM `cs_messages` WHERE `sender` = '{$iPid}' AND UNIX_TIMESTAMP( ) - `when` < 5 LIMIT 1 "; $iLastId = $GLOBALS['MySQL']->getOne($sSQL); if ($iLastId) return 2; // as protection from very often messages
$bRes = $GLOBALS['MySQL']->res("INSERT INTO `cs_messages` SET `sender` = '{$iPid}', `message` = '{$sMessage}', `when` = UNIX_TIMESTAMP()"); return ($bRes) ? 1 : 3; } }
// return input text form function getInputForm() { return file_get_contents('templates/chat.html'); }
// get last 10 messages function getMessages() { $sSQL = " SELECT `a` . * , `cs_profiles`.`name` , UNIX_TIMESTAMP( ) - `a`.`when` AS 'diff' FROM `cs_messages` AS `a` INNER JOIN `cs_profiles` ON `cs_profiles`.`id` = `a`.`sender` ORDER BY `a`.`id` DESC LIMIT 10 "; $aMessages = $GLOBALS['MySQL']->getAll($sSQL); asort($aMessages);
// create list of messages $sMessages = ''; foreach ($aMessages as $i => $aMessage) { $sExStyles = $sExJS = ''; $iDiff = (int)$aMessage['diff']; if ($iDiff < 7) { // less than 7 seconds $sExStyles = 'style="display:none;"'; $sExJS = "<script> $('#message_{$aMessage['id']}').fadeIn('slow'); </script>"; }
$sWhen = date("H:i:s", $aMessage['when']); $sMessages .= '<div class="message" id="message_'.$aMessage['id'].'" '.$sExStyles.'><b>' . $aMessage['name'] . ':</b> ' . $aMessage['message'] . '<span>(' . $sWhen . ')</span></div>' . $sExJS; } return $sMessages; } }
$GLOBALS['MainChat'] = new CChat();
Здесь у нас новый класс для процессора нашего чата. На данный момент он содержит всего 3 функции: acceptMessage, getInputForm и getMessages.
Посмотреть демо | Скачать архив
Внимание! У вас нет прав для просмотра скрытого текста.
Заключение
Надеемся, что наше руководство будет полезным для вас, и вы используете его в своих будущих проектах. Удачи! И не забываем следить за новостями!
Вернуться назад
|