—»     —»   Мощная система для организации чата – Часть 9
  Раздел: Чаты   Комментариев: 1  

Мощная система для организации чата – Часть 9



Сегодня мы приготовили для вас следующую часть руководства по разработке чата на PHP и MySQL. Наш 9-й урок посвящен разработке важной функции: публичным комнатам. Теперь пользователи могут общаться в различных публичных комнатах. Права создания и удаления комнат принадлежат администраторам.

Мощная система для организации чата – Часть 9

Сегодня, как и обычно, мы выложим для вас обновленные исходники нашего развивающегося проекта. Как вам уже известно, весь проект разложен по полочкам: системные классы будут в папке «classes», javascript-файлы в папке «js», таблицы стилей в папке «css», файлы шаблона в папке «templates».

Этап 1 – SQL

Мы добавили новую таблицу в базу данных ‘cs_rooms’. Данная таблица будет содержать в себе записи о комнатах. Пожалуйста, выполните следующий SQL-запрос:

CREATE TABLE `cs_rooms` (
`id` int(11) unsigned NOT NULL auto_increment,
`title` VARCHAR(255) NOT NULL,
`owner` int(11) unsigned NOT NULL,
`when` int(11) NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

INSERT INTO `cs_rooms` (`id`, `title`, `owner`, `when`) VALUES
(NULL, 'Room1', 3, 1338293810),
(NULL, 'Room2', 3, 1338293811),
(NULL, 'Room3', 3, 1338293812);

Мы добавили всего 3 комнаты.

Этап 2 – HTML

Мы обновили шаблон нашего основного окна чата. Добавили id комнаты в двух местах:

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>
<input type="hidden" name="room" value="{room}" />
</form>
<script>
var iRoom = {room};
</script>
<script src="js/chat.js"></script>

Главная страница также подверглась изменениям. Сюда мы внесли некоторые изменения касательно функции комнат:

templates/main_page.html

<!DOCTYPE html>
<html lang="en" >
<head>
<title>Powerful Chat System - Lesson 9</title>
<link href="css/main.css" rel="stylesheet" type="text/css" />
<link href="css/rooms.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 9</h2>
<a href="http://www.script-tutorials.com/powerful-chat-system-lesson-9/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
</header>
<div class="clear"></div>
<div class="container" id="con1">
{form}
{avatar}
</div>
<div class="container" id="con2">
{rooms}
{new_room}

<h2>{chat_name} Chat Block</h2>
<div class="chat_messages">
{chat}
</div>
{input}
</div>

<div class="sidebar">
<div>
<h2>Online Members Block</h2>
{online_members}
</div>
<div>
<h2>Last Members</h2>
{profiles}
</div>
</div>

<div class="priv_dock_wrap"></div>
{priv_js}

</body>
</html>

И, наконец, мы добавили один новый файл шаблона для управления комнатами (здесь мы сможем создавать комнаты или удалять ранее созданные)

templates/new_room.html

<form class="new_room_form" method="post">
<div><input type="text" name="title" /><input type="submit" value="Add room" name="submit" /></div>
<input type="hidden" name="action" value="add_room" />
</form>
<form class="delete_room_form" method="post">
<input type="submit" value="Delete current room" name="submit" />
<input type="hidden" name="room_id" value="{room}" />
<input type="hidden" name="action" value="delete_room" />
</form>
<div class="clear"></div>
<br /><hr />

Этап 3 - CSS

Конечно же, нам нужно оформить вкладки для наших комнат (каждая комната – отдельная css-вкладка):

css/rooms.css

.roomsHolder {
font: bold 12px/35px verdana;
overflow: hidden;
position: relative;
}
.roomsHolder .shadow {
background-color: #888888;
height: 8px;
left: 5%;
position: absolute;
top: -9px;
width: 90%;

/* css3 box shadow */
-webkit-box-shadow: 0 0 10px #000000;
-moz-box-shadow: 0 0 10px #000000;
-o-box-shadow: 0 0 10px #000000;
box-shadow: 0 0 10px #000000;
}
ul.rooms {
display: block;
float: right;
height: 70px;
list-style: none outside none;
margin: 0;
padding: 0 60px;
position: relative;
}
ul.rooms li {
float: left;
margin: 0 5px 0 0;
}
ul.rooms li a {
color: #DDDDDD;
display: block;
padding: 0 10px;
text-decoration: none;

/* css3 box shadow */
-webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9);
-moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9);
-o-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9);
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9);

/* css radius */
-webkit-border-bottom-right-radius: 10px;
-webkit-border-bottom-left-radius: 10px;
-moz-border-radius: 0 0 10px 10px;
-o-border-radius: 0 0 10px 10px;
border-radius: 0 0 10px 10px;

/* css3 transition */
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
}
ul.rooms li a.red {
background-color:#a00;
}
ul.rooms li a.orange {
background-color:#da0;
}
ul.rooms li a.green {
background-color:#060;
}
ul.rooms li a.blue {
background-color:#00a;
}
ul.rooms li a.indigo {
background-color:#2b0062;
}
ul.rooms li a.violet {
background-color:#682bc2;
}
ul.rooms li a:hover, ul.rooms li a.active {
background:#aaa;
color:#fff;
padding:10px 10px 0 10px;
}
ul.rooms li a.red:hover, ul.rooms li a.red.active {
background-color:#c00;
}
ul.rooms li a.orange:hover, ul.rooms li a.orange.active {
background-color:#fc0;
}
ul.rooms li a.green:hover, ul.rooms li a.green.active {
background-color:#080;
}
ul.rooms li a.blue:hover, ul.rooms li a.blue.active {
background-color:#00c;
}
ul.rooms li a.indigo:hover, ul.rooms li a.indigo.active {
background-color:#5b1092;
}
ul.rooms li a.violet:hover, ul.rooms li a.violet.active {
background-color:#8a2be2;
}
.new_room_form {
float: left;
}
.delete_room_form {
float: right;
}

Этап 4 - PHP

Страница index также была изменена. Мы добавили весь необходимый функционал для работы с комнатами: администраторы могут создавать и удалять комнаты. Обычные пользователи (и администраторы) могут писать сообщения в различные комнаты.

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
require_once('classes/CProfiles.php'); // including service class to work with profiles

$sErrors = '';
// join processing
if (! isset($_SESSION['member_id']) && $_POST['Join'] == 'Join') {
$GLOBALS['CProfiles']->registerProfile();
}

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

$sChat = '<h2>You do not have rights to use chat</h2>';
$sInput = $sPrivChatJs = $sRooms = '';
if ($_SESSION['member_id'] && $_SESSION['member_status'] == 'active' && $_SESSION['member_role']) {
if ($_GET['action'] == 'update_last_nav') { // update last navigate time
$iPid = (int)$_SESSION['member_id'];
if ($iPid) {
$GLOBALS['MySQL']->res("UPDATE `cs_profiles` SET `date_nav` = NOW() WHERE `id` = '{$iPid}'");
}
exit;
}

require_once('classes/CChat.php'); // including service class to work with chat

if ($_GET['action'] == 'check_new_messages') { // check for new messages
$iPid = (int)$_SESSION['member_id'];
$iSender = $GLOBALS['MainChat']->getRecentMessage($iPid);

if ($iSender) {
$aSender = $GLOBALS['CProfiles']->getProfileInfo($iSender);
$sName = ($aSender['first_name'] && $aSender['last_name']) ? $aSender['first_name'] . ' ' . $aSender['last_name'] : $aSender['name'];

$oJson = new Services_JSON();
header('Content-type: application/json');
echo $oJson->encode(array('id' => $iSender, 'name' => $sName));
}
exit;
}

if ($_GET['action'] == 'get_private_messages') { // regular updating of messages in chat
$sChat = $GLOBALS['MainChat']->getMessages((int)$_GET['recipient']);
$oJson = new Services_JSON();
header('Content-type: application/json');
echo $oJson->encode(array('messages' => $sChat));
exit;
}

$iRoom = (int)$_GET['room'];

$sNewRoom = '';
if ($_SESSION['member_role'] == 5) {
$aRoomKeys = array('{room}' => $iRoom);
$sNewRoom = strtr(file_get_contents('templates/new_room.html'), $aRoomKeys);
if ($_POST['action'] == 'add_room' && $_POST['title'] != '') {
$GLOBALS['MainChat']->addRoom($_POST['title']);
}
if ($_POST['action'] == 'delete_room' && (int)$_POST['room_id']) {
$GLOBALS['MainChat']->deleteRoom($_POST['room_id']);
}
}

// get all active rooms
$sRooms = $GLOBALS['MainChat']->getRooms($iRoom);

$sChatName = 'Main';
if ($iRoom) {
$aRoomInfo = $GLOBALS['MainChat']->getRoomInfo($iRoom);
$sChatName = $aRoomInfo['title'];
}

// get last messages
$sChat = $GLOBALS['MainChat']->getMessages(0, $iRoom);
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;
}

// add avatar
if ($_POST['action'] == 'add_avatar') {
$iAvRes = $GLOBALS['CProfiles']->addAvatar();
header('Content-Type: text/html; charset=utf-8');
echo ($iAvRes == 1) ? '<h2 style="text-align:center">New avatar has been accepted, refresh main window to see it</h2>' : '';
exit;
}

// get input form
$sInput = $GLOBALS['MainChat']->getInputForm($iRoom);

if ($_POST['message']) { // POST-ing of message
$iPostRoom = (int)$_POST['room'];
$iRes = $GLOBALS['MainChat']->acceptMessage($iPostRoom);

$oJson = new Services_JSON();
header('Content-type: application/json');
echo $oJson->encode(array('result' => $iRes));
exit;
}

if ($_POST['priv_message']) { // POST-ing of private messages
$iRes = $GLOBALS['MainChat']->acceptPrivMessage();

$oJson = new Services_JSON();
header('Content-type: application/json');
echo $oJson->encode(array('result' => $iRes));
exit;
}
$sPrivChatJs = '<script src="js/priv_chat.js"></script>';
}

// get profiles lists
$sProfiles = $GLOBALS['CProfiles']->getProfilesBlock();
$sOnlineMembers = $GLOBALS['CProfiles']->getProfilesBlock(10, true);

// get profile avatar
$sAvatar = $GLOBALS['CProfiles']->getProfileAvatarBlock();

// draw common page
$aKeys = array(
'{chat_name}' => $sChatName,
'{rooms}' => $sRooms,
'{new_room}' => $sNewRoom,
'{form}' => $sLoginForm . $sErrors,
'{chat}' => $sChat,
'{input}' => $sInput,
'{profiles}' => $sProfiles,
'{online_members}' => $sOnlineMembers,
'{avatar}' => $sAvatar,
'{priv_js}' => $sPrivChatJs
);
echo strtr(file_get_contents('templates/main_page.html'), $aKeys);

Следующий измененный файл – класс основного окна чата. Мы добавили возможность для работы с различными комнатами:

classes/CChat.php

<?php

class CChat {

// constructor
function CChat() {}

// add a message to database
function acceptMessage($iPostRoom = 0) {
$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
AND `room` = '{$iPostRoom}'
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(), `room` = '{$iPostRoom}'");
return ($bRes) ? 1 : 3;
}
}

// add a private message to database
function acceptPrivMessage() {
$sName = $GLOBALS['MySQL']->escape($_SESSION['member_name']);
$iPid = (int)$_SESSION['member_id'];
$iRecipient = (int)$_POST['recipient'];
$sMessage = $GLOBALS['MySQL']->escape($_POST['priv_message']);

if ($iPid && $iRecipient && $sName != '' && $sMessage != '') {
$sSQL = "
SELECT `id`
FROM `cs_messages`
WHERE `sender` = '{$iPid}' AND `recipient` = '{$iRecipient}' AND UNIX_TIMESTAMP( ) - `when` < 5
AND `room` = 0
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}', `recipient` = '{$iRecipient}', `message` = '{$sMessage}', `when` = UNIX_TIMESTAMP()");
return ($bRes) ? 1 : 3;
}
}

// return input text form
function getInputForm($iRoom = 0) {
$aKeys = array(
'{room}' => $iRoom
);
return strtr(file_get_contents('templates/chat.html'), $aKeys);
}

// get last 10 messages
function getMessages($iRecipient = 0, $iRoom = 0) {
$sRecipientSQL = 'WHERE `recipient` = 0';
if ($iRecipient > 0) {
$iPid = (int)$_SESSION['member_id'];
$sRecipientSQL = "WHERE (`sender` = '{$iRecipient}' && `recipient` = '{$iPid}') || (`recipient` = '{$iRecipient}' && `sender` = '{$iPid}')";
}

$sRecipientSQL .= " AND `room` = '{$iRoom}'";

$sSQL = "
SELECT `a` . * , `cs_profiles`.`name`, `cs_profiles`.`id` as 'pid' , UNIX_TIMESTAMP( ) - `a`.`when` AS 'diff'
FROM `cs_messages` AS `a`
INNER JOIN `cs_profiles` ON `cs_profiles`.`id` = `a`.`sender`
{$sRecipientSQL}
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']);
$sAvatar = $GLOBALS['CProfiles']->getProfileAvatar($aMessage['pid']);
$sMessages .= '<div class="message" id="message_'.$aMessage['id'].'" '.$sExStyles.'><b><a href="profile.php?id='.$aMessage['pid'].'" target="_blank"><img src="'. $sAvatar .'">' . $aMessage['name'] . ':</a></b> ' . $aMessage['message'] . '<span>(' . $sWhen . ')</span></div>' . $sExJS;
}
return $sMessages;
}

function getRecentMessage($iPid) {
if ($iPid) {
$sSQL = "
SELECT `a` . * , `cs_profiles`.`name`, `cs_profiles`.`id` as 'pid' , UNIX_TIMESTAMP( ) - `a`.`when` AS 'diff'
FROM `cs_messages` AS `a`
INNER JOIN `cs_profiles` ON `cs_profiles`.`id` = `a`.`sender`
WHERE `recipient` = '{$iPid}' AND `room` = 0
ORDER BY `a`.`id` DESC
LIMIT 1
";

$aMessage = $GLOBALS['MySQL']->getRow($sSQL);
$iDiff = (int)$aMessage['diff'];
if ($iDiff < 7) { // less than 7 seconds, = new
return (int)$aMessage['sender'];
}
return;
}
}

function getRandColor() {
$aColors = array('red', 'blue', 'green', 'orange', 'indigo', 'violet');
shuffle($aColors);
return $aColors[0];
}

function getRooms($iRoom = 0) {
$sSQL = "
SELECT *
FROM `cs_rooms`
WHERE 1
";
$aRooms = $GLOBALS['MySQL']->getAll($sSQL);

$sRooms = '';
foreach ($aRooms as $i => $aRoom) {
$sActive = ($iRoom == $aRoom['id']) ? ' active' : '';
$sColor = $this->getRandColor();
$sRooms .= '<li><a class="'.$sColor.$sActive.'" href="index.php?room='.$aRoom['id'].'">'.$aRoom['title'].'</a></li>';
}

$sMainActive = ($iRoom == 0) ? ' active' : '';
$sColor = $this->getRandColor();

return <<<EOF
<div class="roomsHolder">
<ul class="rooms">
<li><a class="{$sColor}{$sMainActive}" href="index.php">Main</a></li>
{$sRooms}
</ul>
<div class="shadow"></div>
</div>
<div class="clear"></div>
EOF;
}

function getRoomInfo($i) {
$sSQL = "
SELECT *
FROM `cs_rooms`
WHERE `id` = '{$i}'
";
$aInfos = $GLOBALS['MySQL']->getAll($sSQL);
return $aInfos[0];
}

function addRoom($sTitleParam) {
$sTitle = $GLOBALS['MySQL']->escape($sTitleParam);
$iPid = (int)$_SESSION['member_id'];

if ($iPid && $sTitle) {
return $GLOBALS['MySQL']->res("INSERT INTO `cs_rooms` SET `title` = '{$sTitle}', `owner` = '{$iPid}', `when` = UNIX_TIMESTAMP()");
}
}
function deleteRoom($sRoomParam) {
$iRoom = (int)$sRoomParam;

if ($iRoom) {
$GLOBALS['MySQL']->res("DELETE FROM `cs_messages` WHERE `room` = '{$iRoom}'");
return $GLOBALS['MySQL']->res("DELETE FROM `cs_rooms` WHERE `id` = '{$iRoom}' LIMIT 1");
}
}
}

$GLOBALS['MainChat'] = new CChat();

Большинство функций (acceptMessage, acceptPrivateMessage, getInputForm, getMessages и getRecentMessages) теперь отлично работают с комнатами. К тому же, мы добавили некоторые новые функции (getRooms, getRoomInfo, addRoom и deleteRoom) для работы с комнатами. Они вовсе несложные.

Этап 5 - javascript

И, наконец, последний отредактированный файл:

js/chat.js

$(function() {
getMessages = function() {
$.getJSON('index.php?action=get_last_messages&room='+iRoom, 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(), room: $('.chat_submit_form input[name=room]').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;
});

// Update last navigation time feature
updateLastNav = function() {
$.getJSON('index.php?action=update_last_nav', function() {

// refresh last nav time
setTimeout(function(){
updateLastNav();
}, 180000); // 3 mins
});
}
updateLastNav();
});

Мы изменили этот файл для того, чтобы получать валидные сообщения (из текущей активной комнаты), и для того, чтобы сообщения отправлялись в конкретные комнаты.

Посмотреть демо | Скачать архивом
Внимание! У вас нет прав для просмотра скрытого текста.
Обнаружили ошибку или мёртвую ссылку?
Выделите проблемный фрагмент мышкой и нажмите CTRL+ENTER.
В появившемся окне опишите проблему и отправьте уведомление Администрации ресурса.
Нужна органическая вечная ссылка из данной статьи? Постовой?
Подробности здесь
Вам понравился материал? Поблагодарить легко!
Будем весьма признательны, если поделитесь этой статьей в социальных сетях:

Ключевые тэги: PHP, MySQL, javascript, общение онлайн
Опубликовал Design FactoRy   Прочитано (раз): 4373   |   Оставлено комментариев: 1
Автор перевода — CoolWebmasters.Com ©   |   Источник материала / оригинал статьи   Распечатать
Другие статьи и новости по теме:
Комментарий #1: 24 апреля 2013 @ 20:21
Написал: Алексей — группа: Гости  
На сайте с: --   |   Публикаций: 0   |   Комментариев: 0
ICQ: --- не указано ---
Спасибо за труды, но простите, чем эта система является мощной? К сожалению, не читал все уроки, только пару и то, просмотрев лишь код. Кроме вульгарного дизайна и слабого юзабилити ничего выдающегося не заметил. Чат как чат
Добавление комментария
Уважаемые пользователи!
При добавлении комментариев на сайт Вам следует учитывать следующее - все комментарии проверяются Администрацией на предмет отсутствия спама. При обнаружении признаков спама, в оставленном Вами комментарии, сам комментарий будет незамедлительно удалён, а Ваш IP-адрес будет забанен без предупреждения! Учётные записи пользователей, рассылающих спам, блокируются/удаляются без права последующего восстановления.

С уважением, Администрация сайта.
* = поля обязательны к заполнению
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Вопрос : Национальная денежная единица России
Подтверждение кода безопасности :

Включите эту картинку для отображения кода безопасности
обновить, если не виден код


Популярные публикации


















Свежие шаблоны сайтов каждый день
С миру по нитке
«    Март 2017    »
ПнВтСрЧтПтСбВс
 12345
6789101112
13141516171819
20212223242526
2728293031