Скрипт особистих повідомлень на PHP jquery. Пишемо чат на рНр

Скрипт особистих повідомлень на PHP jquery. Пишемо чат на рНр

HTML

Як завжди, перший крок присвячений розмітці HTML. Наш документ будується відповідно до HTML5, що дозволяє використовувати новий, більш короткий синтаксис DOCTYPE, та опускати атрибут typeу тегах script.

index.html

Робимо AJAX веб-чат з використанням PHP, MySQL та jQuery | Демонстрація сайту сайт

Для оптимізації завантаження, стилі включені до секцій head, а файли JavaScript підключаються внизу документа, перед закриваючим тегом body.

Для організації прокручується області з рядками чату ми використовуємо плагін jScrollPane. Даний плагін має свої власні стилі, які включаються до секцій head.

Розмітка чату складається з чотирьох основних елементів div- верхньої панелі, контейнера чату, контейнера користувачів та нижньої панелі. Останній divмістить форми для реєстрації користувача та надсилання повідомлення. Форма надсилання повідомлення за замовчуванням прихована і виводиться лише, якщо користувач успішно увійшов до системи чату.

Потім ми включаємо файли JavaScript: бібліотеку jQuery, плагін mousewheel (використовується в jScrollPane), плагін jScrollPane та наш файл script.js.


Схема бази даних

Перш ніж перейти до частини PHP, потрібно спочатку поглянути на організацію чату в базі даних MySQL.

Для нашого скрипту ми використовуємо дві таблиці. В таблиці webchat_users зберігається інформація про учасників чату. Таблиця має поля id , name , gravatar і last_activity . Поле name визначено як унікальне, таким чином запобігається використання імен, що дублюються, в чаті.


Іншим корисною властивістюполя з унікальним індексом є те, що запит на вставку даних завершиться з помилкою та властивість inserted_rows об'єкта MySQLi буде встановлено в значення 0, якщо спробувати вставити рядки, що дублюються. У класі PHP Chatця властивість буде активно використовуватися.

Поле last_activity містить значення часу. Значення оновлюється кожні 15 секунд для кожного користувача. Поле також визначено як індекс, що дозволяє швидко видаляти неактивних користувачів (значення у полі last_activity більше 15 означає, що користувач не переглядає вікно чату).

Таблиця webchat_lines містить записи у чаті. Зверніть увагу, що ми зберігаємо ім'я автора і gravatar тут теж. Таке дублювання дозволяє нам відмовитися від використання витратної директиви. joinпри запиті останніх записів - найчастіше використовуваних нашому додатку.


Визначення таблиць є у файлі tables.sqlу вихідниках. Для створення таблиць можна використовувати текст запитів. Також, при встановленні чату на свій хост, необхідно змінити установки в ajax.phpна дані для з'єднання з базою MySQL.

PHP

Тепер у нас є база даних, давайте обговоримо PHP скрипт, який управляє чатом.

Перший файл, який ми розглянемо, ajax.php. Він обробляє запити AJAXвід клієнтської частини з jQuery та виводить дані у форматі JSON.

ajax.php

/* Конфігурація бази даних. Додайте свої дані */ $dbOptions = array("db_host" => "", "db_user" => "", "db_pass" => "", "db_name" => ""); /* Кінець секції конфігурації бази даних */ error_reporting(E_ALL ^ ​​E_NOTICE); require "classes/DB.class.php"; require "classes/Chat.class.php"; require "classes/ChatBase.class.php"; require "classes/ChatLine.class.php"; require "classes/ChatUser.class.php"; session_name("webchat"); session_start(); if(get_magic_quotes_gpc())( // Видаляємо зайві слеші array_walk_recursive($_GET,create_function("&$v,$k","$v = stripslashes($v);")); array_walk_recursive(__ &$v,$k","$v = stripslashes($v);")); ) try( // З'єднання з базою даних DB::init($dbOptions); $response = array(); // Обробка підтримуваних дій: switch($_GET["action"])( case "login": $response = Chat::login($_POST["name"],$_POST["email"]); break; case "checkLogged" : $response = Chat::checkLogged(); break; case "logout": $response = Chat::logout(); break; ); break; case "getUsers": $response = Chat::getUsers(); break; case "getChats": $response = Chat::getChats($_GET["lastID"]); ("Wrong action"); ) echo json_encode($response); ) catch(Exception $e)( die(json_encode(array("error" => $e->getMessage()))); )

Для зручності використовується оператор switchвизначення дій, які обробляє скрипт. Тут реалізовані підсистеми чату, функціональність входу/виходу та дії на запит списку реплік та користувачів у режимі онлайн.

Висновок здійснюється у формі повідомлень JSON (які зручно обробляти з допомогою jQuery), помилки генерують винятки. Оператор switchрозподіляє всі запити відповідним статичним методам класу Chat, який буде обговорюватися пізніше у цьому розділі.

DB.class.php

Class DB ( private static $instance; private $MySQLi; private function __construct(array $dbOptions)( $this->MySQLi = @ new mysqli($dbOptions["db_host"], $dbOptions["db_user"], $dbOptions[ "db_pass"], $dbOptions["db_name"]), if (mysqli_connect_errno()) ( throw new Exception("Помилка бази даних."); static function init(array $dbOptions)( if(self::$instance instanceof self)( return false; ) self::$instance = new self($dbOptions); ) public static function getMySQLiObject()( return self::$ instance->MySQLi; ) public static function query($q)( return self::$instance->MySQLi->query($q); ) public static function esc($str)( return self::$instance-> MySQLi->real_escape_string(htmlspecialchars($str)); ) )

Клас DB – менеджер бази даних. Конструктор оголошено як privateТаким чином, об'єкт не може бути створений поза межами класу, і ініціалізація можлива лише зі статичного методу init(). Він бере масив з параметрами з'єднання з MySQL і створює екземпляр класу, який міститься в статичній змінній self::$instance. Таким чином, забезпечується існування єдиного з'єднання з базою даних у конкретний момент часу.

Решта класу реалізує комунікацію з базою даних, основу якої лежить статичний метод query().

ChatBase.class.php

/* Базовий клас, який використовується класами ChatLine і ChatUser */ class ChatBase( // Даний конструктор використовується всіма класами чату: public function __construct(array $options)( foreach($options as $k=>$v)( if(isset ($this->$k))( $this->$k = $v; ) ) ) )

Це найпростіший базовий клас. Його основне призначення – визначити конструктор, який отримує масив параметрів, але зберігає лише ті, що визначені у класі.

ChatLine.class.php

/* Рядок чату */ class ChatLine extends ChatBase( protected $text = "", $author = "", $gravatar = ""; public function save()( DB::query(")) text) VALUES ("".DB::esc($this->author)."", "".DB::esc($this->gravatar)."", "".DB::esc($this ->text)."")"); // Повертаємо об'єкт MySQLi класу DB return DB::getMySQLiObject(); ) )

Клас ChatLineє похідним класом від ChatBase. Об'єкт даного класу може бути легко створений за допомогою передачі конструктору масиву з текстом, ім'ям автора та елементом gravatar. Властивість класу gravatarмістить хеш md5 email адреси. Воно потрібне для отримання користувача аватара, відповідного email адресою, із сайту gravatar.com.

Цей клас також визначає метод save, що зберігає об'єкт у базі даних. Оскільки метод повертає об'єкт MySQLi, що міститься в класі DB, ви можете перевірити успішність завершення операції за допомогою властивості affected_rows.

ChatUser.class.php

Class ChatUser extends ChatBase( protected $name = "", $gravatar = ""; public function save()( DB::query(" INSERT INTO webchat_users (name, gravatar) VALUES ("") ->name)."", "".DB::esc($this->gravatar)."")"); return DB::getMySQLiObject(); ) INSERT INTO webchat_users (name, gravatar) VALUES ("".DB::esc($this->name)."", "".DB::esc($this->gravatar)."") ON DUPLICATE KEY UPDATE last_activity = NOW()"); ) )

Клас має властивості nameі gravatar(Зверніть увагу на модифікатор доступу protected- властивості доступні в класі ChatBase і ми можемо встановлювати їх значення в конструкторі).

У класі визначено метод update(), який оновлює поле last_activity значення поточного часу. Таким чином показується, що користувач тримає вікно з відкритим чатом і його треба враховувати як автора в режимі онлайн.

Chat.class.php - Частина 1

/* Клас Chat містить публічні статичні методи, які використовуються в ajax.php */ class Chat( public static function login($name,$email)( if(!$name || !$email)( throw new Exception("Заповніть) всі необхідні поля."); ) if(!filter_input(INPUT_POST,"email",FILTER_VALIDATE_EMAIL))( throw new Exception("Неправильна адреса email."); ) // Підготовка кешу gravatar: $gravatar = md5(strtolower(trim ($email))), $user = new ChatUser(array("name" => $name, "gravatar" => $gravatar)); >affected_rows != 1)( throw new Exception("Це ім'я використовується."); ) $_SESSION["user"] = array("name" => $name, "gravatar" => $gravatar); return array( "status" => 1, "name" => $name, "gravatar" => Chat::gravatarFromHash($gravatar)); ) public static function checkLogged()( $response = array("logged" => false) ; if($_SESSION["user"]["name"])( $response["logged"] = true; $response["loggedAs"] = array("name" => $_SESSION["user"][ "name"], "gravatar" => Chat::gravatarFromHash($_SESSION["user"]["gravatar"]))); ) return $response; ) public static function logout()( DB::query("DELETE FROM webchat_users WHERE name = "".DB::esc($_SESSION["user"]["name"])."")); $_SESSION = array(); unset($_SESSION); return array("status" => 1); )

Цей код виконує всю роботу. В операторі switchу файлі ajax.phpвибиралися дії, що відповідали методам цього класу. Кожен із цих методів повертає масив, який потім конвертується в об'єкт JSON за допомогою функції json_encode()(це відбувається внизу у файлі ajax.php).

Коли користувач входить до системи, його ім'я та gravatarзберігаються як елементи масиву $_SESSIONта стають доступними у наступних запитах.

Chat.class.php - Частина 2

Public static function submitChat($chatText)( if(!$_SESSION["user"])( throw new Exception("Ви вийшли з чату"); ) if(!$chatText)( throw new Exception("Ви не ввели повідомлення ."); ) $chat = новий ChatLine(array("author" => $_SESSION["user"]["name"], "gravatar" => $_SESSION["user"]["gravatar"], " text" => $chatText)); // Метод save повертає об'єкт MySQLi $insertID = $chat->save()->insert_id; return array("status" => 1, "insertID" => $insertID); public static function getUsers()( if($_SESSION["user"]["name"])( $user = new ChatUser(array("name" => $_SESSION["user"]["name"]))) $user->update(); ) // Видаляємо записи чату старше 5 хвилин і користувачів, неактивних протягом 30 секунд DB::query("DELETE FROM webchat_lines WHERE ts< SUBTIME(NOW(),"0:5:0")"); DB::query("DELETE FROM webchat_users WHERE last_activity < SUBTIME(NOW(),"0:0:30")"); $result = DB::query("SELECT * FROM webchat_users ORDER BY name ASC LIMIT 18"); $users = array(); while($user = $result->fetch_object())( $user->gravatar = Chat::gravatarFromHash($user->gravatar,30); $users = $user; ) return array("users" => $users, "total" => DB: :query("SELECT COUNT(*) as cnt FROM webchat_users")->fetch_object()->cnt); ) public static function getChats($lastID)( $lastID = (int)$lastID; $result = DB::query("SELECT * FROM webchat_lines WHERE id > ".$lastID." ORDER BY id ASC"); $chats = array(); while($chat = $result->fetch_object())( // Повертаємо час створення повідомлення у форматі GMT (UTC): $chat->time = array("hours" => gmdate("H" ,strtotime($chat->ts)), "minutes" => gmdate("i",strtotime($chat->ts))); $chats = $chat; ) return array("chats" => $chats); ) public static function gravatarFromHash($hash, $size=23)( return "http://www.gravatar.com/avatar/" .$hash."?size=".$size."&default=". urlencode("http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size=".$size); ) )

jQuery надсилає запити getUsers() кожні 15 секунд. Ми використовуємо цей факт, щоб видалити репліки, які старші за 5 хвилин і неактивних користувачів з бази даних. Потенційно можна було б видаляти дані запису в getChats , але цей запит надходить кожну секунду і додаткове навантаження може вплинути на продуктивність програми.

У методі getChats()використовується функція gmdateвиведення часу у форматі GMT. У клієнтській частині ми використовуємо значення годин і хвилин для встановлення в об'єкті JavaScript, а в результаті час відображається відповідно до часового поясу користувача.

Продовження у другій частині!

Почав помічати на багатьох сайтах наявність або віконця чата або віконця онлайн консультанта. Не секрет, що яндекс відносить наявність на сайті чату або консультанта до позитивних комерційних факторів. У зв'язку з цим я спробував наваять ajax чат для сайту.

Так поїхали писати чат на ajax php. Створюємо файл chat.js, а також відразу створимо файли add.php і get_json.php, але про них пізніше. Створюємо файл chat.php. Підключаємо до нього jquery та chat.js. Створюємо у файлі chat.php поле з ім'ям учасника чату та поле з повідомленням у чат, а також кнопку з id btnSend для надсилання повідомлення. На кнопку з id btnSend у файлі chat.js повішено оброблювач подій клік. Див з id chat будуть виводитися наші чат повідомлення. Нижче показаний список шматка коду з файлу chat.php . Не звертайте уваги на незрозумілі css класи, це класи з bootstrap.

У chat.js обробляємо дані з полів введення та методом post у форматі json відправляємо дані в add.php. Шматок коду з chat.js нижче.

$("#btnSend").click(function(elem)( //при кліку отримуємо повідомлення з полів з ід name і text var name = $("#name").val(); var text = $("# text").val(); //і методом POST у форматі json відправляємо їх в add.php $.post("add.php", (name: name, text: text), function()( //поле text стираємо(тобто робимо порожнім "") $("#text").attr("value", ""); )); ));

У файлі add.php ми отримуємо дані. Звичайно їх треба було б перевірити після отримання, але це ми поки що опустимо. Додаємо до даних дату та записуємо їх у файл messages.txt в один рядок з унікальним роздільником "_". Так само для того, щоб файл не розрісся до великих розмірів, зроблено захист від переповнення. При досягненні у файлі messages.txt рядків повідомлень більше 100 всі рядки стираються крім останніх п'яти. Вони списуються наново. Нижче лістинг add.php.

100 if(count($strings)>100)( //отримуємо всі рядки з файлу у вигляді нумерованого масиву $textarr=file("messages.txt"); $arr=array_slice($textarr, -5); //переписуємо дані у файл записуємо тільки //останні 5 рядків масиву $f = fopen("messages.txt", "w+"); //у циклі записуємо дані у файл, //кожне значення масиву на новому рядку у файлі foreach($arr as $ar)( $f = fopen("messages.txt", "a+");//відкрили файл fwrite($f, $ar);//запис fclose($f);//закрили файл ) ) $ f = fopen("messages.txt", "a+");// відкрили файл fwrite($f, date("Y-m-d H:i:s") . "___"); name . "___");//запис у файл fwrite($f, $text . "\n");//запис і додали кінець рядка fclose($f);//закрили файл ) ?>

Все, всі наші повідомлення пишуться у файл. Тепер нам потрібно зробити так, щоб ці повідомлення виводилися на екран. Для цього напишемо у файлі chat.js функцію chatRequest(). Ця функція звертається до файлу get_json.php і передає параметр __maxId . Параметр _maxId вказує скільки повідомлень у нас є на Наразі. За замовчуванням на початку стоїть 0. Відповідно для початку __maxId визначаємо як глобальну змінну.

Function chatRequest()( // Відправлення запиту методом POST. $.post("get_json.php", (maxId: _maxId), chatResult, "json"); )

Так само функції chatRequest() визначено, що при вдалому виконанні запиту дані відповіді повертаються у форматі json і викликається функція chatResult з файлу chat.js . Але спочатку розберемо файл get_json.php .

Файл get_json.php приймає дані, обчислює рядок, який не відображається на екрані, робить з неї масив, упаковує у формат json і відправляє у функцію chatResult(msgs) .

ChatResult дописує дані отриманого рядка масив _messages . Ми його оголосили на початку файлу і зробили його масивом. І потім функція заново виводить всі написані повідомлення в циклі з масиву _messages див з id #chat . Зробив так, щоб виводилося лише п'ять останніх повідомлень. Для парного та непарного повідомлення виводиться своя верстка. Для верстки я знову ж таки використовую бутстрап. Лістинг функції ChatResult.

Function chatResult(msgs)( // Додавання нових повідомлень до масиву. for(var i = 0; i =0; i--) ( var m = _messages[i]; //перевірка що повідомлення парне if (i%2= =1)( //верстка html +="

"; html +="
"; html +="

"+m.text+" "+m.dt+"

"; html +="
"; html +="

"+m.text+" "+m.dt+"

"; ) ) // повідомлень у фаїлі більше 5 )else( for (var i = _messages.length - 1; i >
"; html +="
"; html +="

"+m.text+" "+m.dt+"

"; )else( //верстка html +="
"; html +="
"; html +="

"+m.text+" "+m.dt+"

Для того щоб у нас чат постійно оновлювався ми робимо постійні запити до функції chatRequest() з періодичністю 2 сек.

// Запитуємо повідомлення кожні 2 секунди setInterval(chatRequest, 2000);

Ну ось ми і написали простий чат на ajax php для сайту. Для повноти картини покажемо повний список файлів chat.js

Var _maxId; var _messages; $(document).ready(function()( // Ініціалізація. _maxId = 0; _messages = ; chatRequest(); // Запрошуємо кожні 2 секунди setInterval(chatRequest, 2000); $("#btnSend").click( function(elem)( //при кліку отримуємо повідомлення з полів з ід name і text var name = $("#name").val(); var text = $("#text").val(); // і методом POST у форматі json відправляємо їх в add.php $.post("add.php", (name: name, text: text), function()( //поле text стираємо(тобто робимо порожнім "") $( "#text").attr("value", ""); )); )); )); function chatRequest() ( // Відправка запиту методом POST. $.post("get_json.php", (maxId: _maxId), chatResult, "json"); ) function chatResult(msgs)( // Додавання нових повідомлень до масиву. for(var i = 0; i =0; i--) ( var m = _messages[i]; //перевірка що повідомлення парне if (i%2==1)( //верстка html +="

"; html +="
"; html +="

"+m.text+" "+m.dt+"

"; )else( //верстка html +="
"; html +="
"; html +="

"+m.text+" "+m.dt+"

"; ) ) // повідомлень у фаїлі більше 5 )else( for (var i = _messages.length - 1; i >= _messages.length-5; i--)( var m = _messages[i]; //перевірка що повідомлення парне if (i%2==1)( //верстка html +="
"; html +="
"; html +="

"+m.text+" "+m.dt+"

"; )else( //верстка html +="
"; html +="
"; html +="

"+m.text+" "+m.dt+"

"; ) ) ) //виводимо всі повідомлення $("#chat").html(html); )

update 5.10.16

Заткнув найпростішу дірку від найпростішої XSS атаки. Усі просто задовбали ламати чат)). Було ліньки фільтрувати вхідні дані, але довелося переробити. Функція фільтрації.

/*ф-я фільтрації*/ function myclear($dt)( $dt=stripslashes($dt); $dt=strip_tags($dt); $dt=trim($dt); return $dt; )

тепер файл add.php виглядає так

/*ф-я фільтрації*/ function myclear($dt)( $dt=stripslashes($dt); $dt=strip_tags($dt); $dt=trim($dt); return $dt; ) $name = myclear($_POST["name"]); //фільтруємо $text = myclear($_POST["text"]); //було раніше //$name = $_POST["name"]; //$text = $_POST["text"]; if(($name != "") && ($text != ""))( $strings = file("messages.txt"); if(count($strings)>100)( //отримуємо всі рядки з файлу у вигляді нумерованого масиву $textarr=file("messages.txt"); $arr=array_slice($textarr, -5); //переписуємо дані у файл записуємо тільки останні 3 рядки масиву $f = fopen("messages.txt ", "w+"); //в циклі записуємо дані у файл, кожне значення масиву на новому рядку у файлі foreach($arr as $ar)( $f = fopen("messages.txt", "a+");/ /відкрили файл fwrite($f, $ar);//запис fclose($f);//закрили файл ) ) $f = fopen("messages.txt", "a+");//відкрили файл fwrite($ f, date("Y-m-d H:i:s") . "___");//запис fwrite($f, $name . "___");//запис у файл fwrite($f, $text . "\ n");//запис і додали кінець рядка fclose($f);//закрили файл )

Живе спілкування на сайті не залишить байдужим відвідувача, адже завжди можна написати в чат, і тобі щось та й дадуть відповідь, на сайтах все рідше можна зустріти цю функцію, розробники почали забувати про неї, посилаючись більше на форуми та коментарі. Але якщо є можливість поставити чат на сайті, то не потрібно втрачати таку можливість, користувачі будуть лише вдячні. У даному уроці ми розглянемо, як створити вельми цікавий чат для сайту, з використанням сервісів аватарів, що надасть спілкуванню більш приємної форми. Для того, щоб створити такий AJAX чат ми будемо використовувати PHP, MySQL та jQuery. Для початку ми розглянемо розмітку HTML, документ якого будується відповідно до HTML5, що дозволяє використовувати новий, більш короткий синтаксис DOCTYPE, та опускати атрибут type у тегах script.
index.html

Як створити чат для сайту за допомогою PHP Демонстрація для сайту RUDEBOX

Для організації прокручується з рядками чату ми використовуємо плагін jScrollPane. Цей плагін має свої власні стилі, які включаються до секції head.
Розмітка чату складається з чотирьох основних елементів div – верхньої панелі, контейнера чату, контейнера користувачів та нижньої панелі. Останній div містить форми для реєстрації користувача та надсилання повідомлення. Форма надсилання повідомлення за замовчуванням прихована і виводиться лише, якщо користувач успішно увійшов до системи чату.
Примітка! Визначення таблиць є у файлі tables.sql у вихідниках. Для створення таблиць можна використовувати текст запитів. Також, при установці чату на власний хост, необхідно поміняти установки в ajax.php на ваші дані для з'єднання з базою MySQL.
Коли Ви створили таблицю і зробили все, що сказано в примітці, то обговоримо скрипт PHP, який керує чатом. Перший файл, який ми розглянемо ajax.php. Він обробляє запити AJAX від клієнтської частини з jQuery та виводить дані у форматі JSON.
ajax.php

/* Конфігурація бази даних. Додайте свої дані */ $dbOptions = array("db_host" => "", "db_user" => "", "db_pass" => "", "db_name" => ""); /* Кінець секції конфігурації бази даних */ error_reporting(E_ALL ^ ​​E_NOTICE); require "classes/DB.class.php"; require "classes/Chat.class.php"; require "classes/ChatBase.class.php"; require "classes/ChatLine.class.php"; require "classes/ChatUser.class.php"; session_name("webchat"); session_start(); if(get_magic_quotes_gpc())( // Видаляємо зайві слеші array_walk_recursive($_GET,create_function("&$v,$k","$v = stripslashes($v);")); array_walk_recursive(__ &$v,$k","$v = stripslashes($v);")); ) try( // З'єднання з базою даних DB::init($dbOptions); $response = array(); // Обробка підтримуваних дій: switch($_GET["action"])( case "login": $response = Chat::login($_POST["name"],$_POST["email"]); break; case "checkLogged" : $response = Chat::checkLogged(); break; case "logout": $response = Chat::logout(); break; ); break; case "getUsers": $response = Chat::getUsers(); break; case "getChats": $response = Chat::getChats($_GET["lastID"]); ("Wrong action"); ) echo json_encode($response); ) catch(Exception $e)( die(json_encode(array("error" => $e->getMessage()))); )

Для зручності використовують оператор switch для визначення дій, які обробляє скрипт. Тут реалізовані підсистеми чату, функціональність входу/виходу та дії на запит списку реплік та користувачів у режимі онлайн.
Висновок здійснюється у формі повідомлень JSON (які зручно обробляти jQuery), помилки генерують винятки. Оператор switch розподіляє всі запити відповідним статичним методам класу Chat, який обговорюватиметься пізніше у цьому розділі.
DB.class.php

DB ( private static $instance; private $MySQLi; private function __construct(array $dbOptions)( $this->MySQLi = @ new mysqli($dbOptions["db_host"], $dbOptions["db_user"], $dbOptions[" db_pass"], $dbOptions["db_name"]); if (mysqli_connect_errno()) ( throw new Exception("Помилка бази даних."); ) $this->MySQLi->set_charset("utf8"); ) public static function init(array $dbOptions)( if(self::$instance instanceof self)( return false; ) self::$instance = new self($dbOptions); ) public static function getMySQLiObject()( return self::$instance ->MySQLi; ) public static function query($q)( return self::$instance->MySQLi->query($q); ) public static function esc($str)( return self::$instance->MySQLi ->real_escape_string(htmlspecialchars($str)); ) )

Клас DB – менеджер бази даних. Конструктор оголошений як private, таким чином, об'єкт не може бути створений поза межами класу, і ініціалізація можлива лише зі статичного методу init(). Він бере масив з параметрами з'єднання з MySQL і створює екземпляр класу, який міститься в статичній змінній self::$instance. Таким чином, забезпечується існування єдиного з'єднання з базою даних у конкретний момент часу.
Решта класу реалізує комунікацію з базою даних, основу якої лежить статичний метод query().
ChatBase.class.php

/* Базовий клас, який використовується класами ChatLine і ChatUser */ class ChatBase( // Даний конструктор використовується всіма класами чату: public function __construct(array $options)( foreach($options as $k=>$v)( if(isset ($this->$k))( $this->$k = $v; ) ) ) )

Це найпростіший базовий клас. Його основне призначення – визначити конструктор, який отримує масив параметрів, але зберігає лише ті, що визначені у класі.
ChatLine.class.php

/* Рядок чату */ class ChatLine extends ChatBase( protected $text = "", $author = "", $gravatar = ""; public function save()( DB::query(")) text) VALUES ("".DB::esc($this->author)."", "".DB::esc($this->gravatar)."", "".DB::esc($this ->text)."")"); // Повертаємо об'єкт MySQLi класу DB return DB::getMySQLiObject(); ) )

Клас ChatLine є похідним класом від ChatBase. Об'єкт цього класу може бути легко створений за допомогою передачі конструктору масиву з текстом, ім'ям автора та елементом gravatar. Властивість класу gravatar містить хеш md5 email адреси. Воно потрібне для отримання користувача аватара, що відповідає email адресою, з сайту gravatar.com.
Цей клас також визначає метод save, який зберігає об'єкт у базі даних. Оскільки метод повертає MySQLi об'єкт, що міститься в класі DB, ви можете перевірити успішність завершення операції за допомогою властивості affected_rows.
ChatUser.class.php

Class ChatUser extends ChatBase( protected $name = "", $gravatar = ""; public function save()( DB::query(" INSERT INTO webchat_users (name, gravatar) VALUES ("") ->name)."", "".DB::esc($this->gravatar)."")"); return DB::getMySQLiObject(); ) INSERT INTO webchat_users (name, gravatar) VALUES ("".DB::esc($this->name)."", "".DB::esc($this->gravatar)."") ON DUPLICATE KEY UPDATE last_activity = NOW()"); ) )

Клас має властивості name та gravatar (зверніть увагу на модифікатор доступу protected – властивості доступні у класі ChatBase, і ми можемо встановлювати їх значення у конструкторі).
У класі визначено метод update(), який оновлює поле last_activity значенням поточного часу. Таким чином показується, що користувач тримає вікно з відкритим чатом і його треба враховувати як автора в режимі онлайн.
Chat.class.php

/* Клас Chat містить публічні статичні методи, які використовуються в ajax.php */ class Chat( public static function login($name,$email)( if(!$name || !$email)( throw new Exception("Заповніть) всі необхідні поля."); ) if(!filter_input(INPUT_POST,"email",FILTER_VALIDATE_EMAIL))( throw new Exception("Неправильна адреса email."); ) // Підготовка кешу gravatar: $gravatar = md5(strtolower(trim ($email))), $user = new ChatUser(array("name" => $name, "gravatar" => $gravatar)); >affected_rows != 1)( throw new Exception("Це ім'я використовується."); ) $_SESSION["user"] = array("name" => $name, "gravatar" => $gravatar); return array( "status" => 1, "name" => $name, "gravatar" => Chat::gravatarFromHash($gravatar)); ) public static function checkLogged()( $response = array("logged" => false) ; if($_SESSION["user"]["name"])( $response["logged"] = true; $response["loggedAs"] = array("name" => $_SESSION["user"][ "name"], "gravatar" => Chat::gravatarFromHash($_SESSION["user"]["gravatar"]))); ) return $response; ) public static function logout()( DB::query("DELETE FROM webchat_users WHERE name = "".DB::esc($_SESSION["user"]["name"])."")); $_SESSION = array(); unset($_SESSION); return array("status" => 1); )

Цей код виконує всю роботу. В операторі switch у файлі ajax.php вибиралися дії, які відповідали методам цього класу. Кожен із цих методів повертає масив, який потім конвертується в об'єкт JSON за допомогою функції json_encode() (це відбувається внизу у файлі ajax.php).
Коли користувач входить до системи, його ім'я та gravatar зберігаються як елементи масиву $_SESSION і стають доступними у наступних запитах.
Chat.class.php

Public static function submitChat($chatText)( if(!$_SESSION["user"])( throw new Exception("Ви вийшли з чату"); ) if(!$chatText)( throw new Exception("Ви не ввели повідомлення ."); ) $chat = новий ChatLine(array("author" => $_SESSION["user"]["name"], "gravatar" => $_SESSION["user"]["gravatar"], " text" => $chatText)); // Метод save повертає об'єкт MySQLi $insertID = $chat->save()->insert_id; return array("status" => 1, "insertID" => $insertID); public static function getUsers()( if($_SESSION["user"]["name"])( $user = new ChatUser(array("name" => $_SESSION["user"]["name"]))) $user->update(); ) // Видаляємо записи чату старше 5 хвилин і користувачів, неактивних протягом 30 секунд DB::query("DELETE FROM webchat_lines WHERE ts< SUBTIME(NOW(),"0:5:0")"); DB::query("DELETE FROM webchat_users WHERE last_activity < SUBTIME(NOW(),"0:0:30")"); $result = DB::query("SELECT * FROM webchat_users ORDER BY name ASC LIMIT 18"); $users = array(); while($user = $result->fetch_object())( $user->gravatar = Chat::gravatarFromHash($user->gravatar,30); $users = $user; ) return array("users" => $users, "total" => DB: :query("SELECT COUNT(*) as cnt FROM webchat_users")->fetch_object()->cnt); ) public static function getChats($lastID)( $lastID = (int)$lastID; $result = DB::query("SELECT * FROM webchat_lines WHERE id > ".$lastID." ORDER BY id ASC"); $chats = array(); while($chat = $result->fetch_object())( // Повертаємо час створення повідомлення у форматі GMT (UTC): $chat->time = array("hours" => gmdate("H" ,strtotime($chat->ts)), "minutes" => gmdate("i",strtotime($chat->ts))); $chats = $chat; ) return array("chats" => $chats); ) public static function gravatarFromHash($hash, $size=23)( return "http://www.gravatar.com/avatar/" .$hash."?size=".$size."&default=". urlencode("http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size=".$size); ) )

У методі getChats() використовується функція gmdate виведення часу у форматі GMT. У клієнтській частині ми використовуємо значення годин і хвилин для встановлення в об'єкті JavaScript, а в результаті час відображається відповідно до часового поясу користувача.
Стилі чату містяться у файлі chat.css. Стилі не залежать від решти сторінки і їх легко вбудувати в існуючий сайт. Потрібно лише увімкнути розмітку HTML, стилі та файли JavaScript.
chat.css

/* Основний контейнер чату */ #chatContainer( width:510px; margin:100px auto; position:relative; ) /* Верхня панель */ #chatTopBar( height:40px; background:url("../img/solid_gray.jpg ") repeat-x #d0d0d0; border:1px solid #fff; margin-bottom:15px; position:relative; color:#777; text-shadow:1px 1px 0 #FFFFFF; ) #chatTopBar .name( position:absolute; top: 10px; chat( background:url("../img/chat_line_bg.jpg") repeat-x #d5d5d5; min-height:24px; padding:6px; border:1px solid #FFFFFF; padding:8px 6px 4px 37px; position:relative .chat:last-child( margin-bottom:0; ) .chat span( color:#777777; text-shadow:1px 1px 0 #FFFFFF; font-size:12px; ) . chat .text( color:#444444; display:inline-block; font-size:15px; overflow:hidden; vertical-align:top; width:190px; ) .chat .gravatar( background:url("http:// www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size=23") no-repeat; left:7px; position:absolute; top:7px; ) .chat img( display:block; visibility:hidden; ) .chat .time( position:absolute; right:10px; top:12px; font-size:11px; ) .chat .author( margin-right:6px; font -size:11px;

Починається все із завдання стилів для div #chatContainer. Він центрується горизонтально за допомогою margin:100px auto; . Цей div поділяється на верхню панель, область чату, область користувачів та нижню панель.
Верхня панель виводить інформацію про зареєстрованого користувача. Вона отримує відносне позиціонування, так що аватар, ім'я та кнопка "вийти" розташовуються відповідно.
Потім слідує div, який містить усі рядки чату – #chatLineHolder. Даний div має фіксовану висоту і ширину, а в частині даного уроку, присвячену jQuery, ми використовуємо плагін jScrollPane для перетворення його в область з прокручуванням контенту з боковим слайдером.
chat.css

/* Область користувача */ #chatUsers( background-color:#202020; border:1px solid #111111; height:360px; position:absolute; right:0; top:56px; width:150px; ) #chatUsers .user( :url("http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size=30") no-repeat 1px 1px #444444; border:1px solid #111111; 0 10px; width:32px; ) #chatUsers .user img( border:1px solid #444444; display:block; visibility:hidden; ) /* Нижня панель */ #chatBottomBar( background:url("../img/solid_gray .jpg") repeat-x #d0d0d0; position:relative; padding:10px; border:1px solid #fff; ) #chatBottomBar .tip( position:absolute; width:0; height:0; border:10px solid transparent; border -bottom-color:#eeeeee; top:-20px; left:20px; ) #chatContainer input( background:url("../img/input_bg.jpg") repeat-x #dcdcdc; /26px Calibri,Arial,sans-serif;color:#777; border:1px solid; border-color:#c1c1c1 #eee #eee #c1c1c1; padding:0 5px; margin-right:5px; width:185px; outline: none; ) #submitForm( display:none; )

У другій частині файлу стилів ми оформляємо контейнер #chatUsers та елементи div для користувача. Кожен активний користувач чату представлений зображенням gravatar розміром 32 на 32 пікселі. Стандартне зображення використовується як фон, і коли реальне зображення завантажується з сервера gravatar.com, воно виводиться зверху. Так запобігається подразливе мерехтіння, яке зазвичай з'являється в момент завантаження зображення.
Решта коду пов'язана з нижньою панеллю та формою відправлення. Елемент div .tip стає трикутником, зробленим з використанням CSS, за рахунок встановлення нульової висоти та ширини, при цьому ширина обведення встановлюється великою.
chat.css

/* Зміна стилів за замовчуванням для jScrollPane */ .jspVerticalBar( background:none; width:20px; ) .jspTrack( background-color:#202020; border:1px solid #111111; width:3px;. right jspDrag ( background:url("../img/slider.png") no-repeat; width:20px; left:-9px; height:20px !important; margin-top:-5px; ) .jspDrag:hover( background -position:left bottom; ) /* Додаткові стилі */ a.logoutButton( background-color:#bbb; border:1px solid #eee !important; color:#FFFFFF !important; font-size:12px; padding:5px 9px position:absolute;right:10px;text-shadow:1px 1px 0 #888;top:7px;-moz-box-shadow:0 0 7px #888 inset; box-shadow:0 0 7px #888 inset; ) a.logoutButton:hover( text-shadow:1px 1px 0 #888; -moz-box-shadow:0 0 7px #666 inset; -webkit-box-shadow: 0 0 7px #666 inset; box-shadow:0 0 7px #666 inset; ) #chatContainer .blueButton( background:url("../img/button_blue.png") no-repeat; :#516D7F !important; display:inline-block; font-size:13px; height:29px; text-align:center; text-shadow:1px 1px 0 rgba(255, 255, 255, 0.4); width:75px; margin:0; cursor: pointer; ) #chatContainer .blueButton:hover( background-position:left bottom; ) p.noChats, #chatUsers .count( clear:both; font-size:12px; padding:10px; text-align:center; text-shadow:1px 1px 0 #111111; ) #chatUsers .count( font-size:11px; ) .rounded( -moz-border-radius:4px; -webkit-border-radius:4px; border-radius:4px; ) #chatErrorMessage( width :100%;top:0;left:0;position:fixed;background-color:#ab0909;border-bottom:1px solid #d32a2a; font-size:23px; #fff;text-shadow:1px 1px 0 #940f0f;

Перейдемо до останньої частини нашого уроку – коду jQuery. Чат працює, отримуючи події від форм реєстрації та відправлення повідомлення, а також від кнопки "Вийти", а також за розкладом надсилаються запити AJAX до сервера, щоб перевірити наявність нових повідомлень і користувачів.
PHP частина обробляє запити AJAX у файлі ajax.php. jQuery генерує такі запити AJAX:

  • Вхід користувача до системи: один запит POST;
  • Вихід користувача із системи: один запит POST;
  • Перевірка користувачів, які знаходяться в режимі он-лайн: виконується кожні 15 секунд;
  • Перевірка нових записів: запит GET генерується щосекунди. Таке функціонування може призвести до дуже високого навантаження на веб-сервер, тому скрипт оптимізований, і в залежності від активності чату, період генерації запиту може бути збільшений до 15 секунд.
Ми визначили функції обгортки для функцій AJAX jQuery $.get і $.post, які допомагають заповнювати довгі параметри для генерації запиту.
Також весь код чату організовано в один об'єкт chat. Він містить кілька зручних методів.
script.js

$(document).ready(function()( // Запускаємо метод init, коли документ буде готовий: chat.init(); )); var chat = ( // data містить змінні для використання в класах: data: ( lastID: 0, noActivity: 0 ), // Init прив'язує обробники подій та встановлює таймери: init: function()( // Використовуємо плагін jQuery defaultText, включений внизу: $("#name").defaultText("Псевдонім"); $("#email").defaultText("Email (використовується Gravatar)"); // Конвертуємо div #chatLineHolder в jScrollPane, // зберігаємо API плагіна в chat.data: chat.data.jspAPI = $("#chatLineHolder").jScrollPane(( verticalDragMinHeight: 12, verticalDragMaxHeight: 12 )).data("jsp"); // Використовуємо змінну working для запобігання // множинних форми: var working = false; // Реєструємо персону в чаті: $("#loginForm"). ): $.tzPOST("login",$(this).serialize(),function(r)( working = false; if(r.error)( chat.displayError(r.error); ) else chat.login( r.name, r.gravatar); )); return false; ));

Метод init() призначений для прив'язки обробників подій до чату та запуску функцій таймера, які використовуються для перевірки розкладу наявності нових записів у чаті та списку користувачів в режимі онлайн. Ми використовуємо власні функції-обгортки $.tzGET і $.tzPOST. Вони приймають на себе весь тягар роботи за завданням довгого списку параметрів для запитів AJAX.
script.js

// Надсилаємо дані нового рядка чату: $("#submitForm").submit(function()( var text = $("#chatText").val(); if(text.length == 0)( return false; ) if(working) return false, working = true; .data.name, gravatar: chat.data.gravatar, text: text.replace(// g, ">"))); // Використовуємо метод addChatLine, щоб додати чат на екран // негайно, не чекаючи завершення запиту AJAX: chat.addChatLine($.extend((),params)); // Використовуємо метод tzPOST, щоб відправити чат // через запит POST AJAX: $.tzPOST("submitChat",$(this).serialize(),function(r)( working = false; $("#chatText")). val(""); $("div.chat-"+tempID).remove(); params["id"] = r.insertID; chat.addChatLine($.extend((),params)); )) ; return false; )); // Відключаємо користувача: $("a.logoutButton").live("click",function()( $("#chatTopBar > span").fadeOut(function()( $(this).remove(); ) );$("#submitForm").fadeOut(function()( $("#loginForm").fadeIn(); )); $.tzPOST("logout"); return false; )); // Перевіряємо стан підключення користувача (оновлення браузера) $.tzGET("checkLogged",function(r)(if(r.logged)( chat.login(r.loggedAs.name,r.loggedAs.gravatar); )) ; // Самовиповнюються функції таймауту (function getChatsTimeoutFunction()( chat.getChats(getChatsTimeoutFunction); ))(); (function getUsersTimeoutFunction()( chat.getUsers(getUsersTimeoutFunction); ))(); ),

У другій частині скрипту ми продовжуємо прив'язку обробників подій. У функції надсилання форми можна помітити, що коли користувач створює новий запис у чаті, створюється тимчасовий рядок, який негайно виводиться у вікно чату, без очікування завершення запиту AJAX. Як тільки запис буде завершено, тимчасовий рядок видаляється з екрана. Так користувач отримує відчуття, що чат працює блискавично, в той час як реальний запис відбувається у фоновому режимі.
Наприкінці цього шматка коду запускаються дві найменовані функції, що самовиконуються. Ці функції будуть передаватися як параметри методам chat.getChats() або chat.getUsers() відповідно, таким чином, можуть бути встановлені додаткові таймати.
script.js

// Метод login приховує дані реєстрації користувача // і виводить форму введення повідомлення login: function(name,gravatar)( chat.data.name = name; chat.data.gravatar = gravatar; $("#chatTopBar").html( chat.render("loginTopBar",chat.data)); $("#loginForm").fadeOut(function()( $("#submitForm").fadeIn(); $("#chatText").focus( ); )); ), // Метод render генерує розмітку HTML, // яка потрібна для інших методів: render: function(template,params)( var arr = ; switch(template)( case "loginTopBar": arr = [ " ", "",params.name, "Вийти"]; break; case "chatLine": arr = [ "

","",params.author, ":",params.text,"",params.time,"
"]; break; case "user": arr = [ "
" ]; break; ) // Єдиний метод join для масиву виконується // швидше, ніж множинні злиття рядків return arr.join(""); ),

У цій частині коду уваги вимагає метод render(). Він збирає шаблон, залежно від параметра template. Метод потім створює і повертає запитуваний код HTML, вбудовуючи значення другого параметра об'єкта params.
script.js

// Метод addChatLine додає рядок чату на сторінку addChatLine: function(params)( // Усі покази часу виводяться у форматі часового поясу користувача var d = new Date(); if(params.time) ( // PHP повертає час у форматі UTC (GMT).Ми використовуємо його для формування об'єкта date // і подальшого виведення у форматі часового поясу користувача.//JavaScript конвертує його для нас. time = (d.getHours()< 10 ? "0" : "") + d.getHours()+":"+ (d.getMinutes() < 10 ? "0":"") + d.getMinutes(); var markup = chat.render("chatLine",params), exists = $("#chatLineHolder .chat-"+params.id); if(exists.length){ exists.remove(); } if(!chat.data.lastID){ // Если это первая запись в чате, удаляем // параграф с сообщением о том, что еще ничего не написано: $("#chatLineHolder p").remove(); } // Если это не временная строка чата: if(params.id.toString().charAt(0) != "t"){ var previous = $("#chatLineHolder .chat-"+(+params.id - 1)); if(previous.length){ previous.after(markup); } else chat.data.jspAPI.getContentPane().append(markup); } else chat.data.jspAPI.getContentPane().append(markup); // Так как мы добавили новый контент, нужно // снова инициализировать плагин jScrollPane: chat.data.jspAPI.reinitialise(); chat.data.jspAPI.scrollToBottom(true); },

Метод addChat() отримує як параметр об'єкт, який містить рядок чату, ім'я автора та gravatar, і вставляє рядок чату у відповідне місце у контейнері div#chatContainer. Кожен рядок чату (якщо він не є тимчасовим) має унікальний ID, який призначається MySQL. Цей id як ім'я класу для рядка чату у форматі chat-123.
Коли метод addChat() виконується, він перевіряє існування попереднього рядка (для chat-123 перевірятиметься наявність chat-122). Якщо вона існує, метод вставляє новий рядок після неї. Якщо ні, то просто додає новий рядок до div. Така проста техніка керує вставкою рядків у правильному порядку та підтримує його протягом усієї роботи чату.
script.js

// Даний метод запитує останній запис у чаті // (починаючи з lastID), і додає його на сторінку. getChats: function(callback)( $.tzGET("getChats",(lastID: chat.data.lastID),function(r)( for(var i=0;i) Нічого ще не написано

"); ) // Встановлюємо таймот для наступного запиту // залежно від активності чату: var nextRequest = 1000; // 2 секунди if(chat.data.noActivity > 3)( nextRequest = 2000; ) if(chat.data.noActivity > 10)( nextRequest = 5000; ) // 15 секунд if(chat.data.noActivity > 20)( nextRequest = 15000; ) setTimeout(callback,nextRequest); )); ), // Запит списку всіх користувачів. getUsers: function(callback)( $.tzGET("getUsers",function(r)( var users = ; for(var i=0; i)< r.users.length;i++){ if(r.users[i]){ users.push(chat.render("user",r.users[i])); } } var message = ""; if(r.total<1){ message = "Никого нет в онлайне"; } else { message = "В онлайне: " + r.total; } users.push("

"+message+"

"); $("#chatUsers").html(users.join("")); setTimeout(callback,15000); )); ),

У цій частині коду відбувається керування запитами AJAX. У методі getChats() визначається, коли знову виконуватиметься функція залежно від властивості noActivity локального об'єкта даних. При кожному запиті, який не повертає нових рядків чату, ми збільшуємо лічильник. Якщо він досягає певного порогу, наступний запит буде генеруватися із затримкою.
script.js

// Даний метод виводить повідомлення про помилку вгорі сторінки: displayError: function(msg)( var elem = $("

",( id: "chatErrorMessage", html: msg )); elem.click(function()( $(this).fadeOut(function()( $(this).remove(); )); )); setTimeout (function()( elem.click(); ),5000); elem.hide().appendTo("body").slideDown(); ) );// Формування GET & POST: $.tzPOST = function(action ,data,callback)( $.post("php/ajax.php?action="+action,data,callback,"json"); ) $.tzGET = function(action,data,callback)( $.get( php/ajax.php?action="+action,data,callback,"json"); ); element.data("defaultText",value); ).blur(function()( if(element.val() == "" || element.val() == value)( element.addClass("defaultText").val(value); ) )); element.blur(); )

В останній частині коду визначаються допоміжні функції та методи. Метод displayError() показує червоний рядок у верхній частині екрана, якщо відбувається помилка. Потім визначаються функції-обгортки $.tzGET і $.tzPOST, і плагін defaultText, який виводить текст, що заповнює для полів введення тексту.

Матеріал представлений виключно для ознайомлення.

Думаю, що кожен із Вас знає, що таке чат. І дуже часто на сайтах можна зустріти або маленькі чати, або досить великі та складні. У цій статті я опишу принцип створення чату. Зверніть увагу, що в цій статті не буде готового коду скопіював-вставив", а лише алгоритм, за допомогою якого Ви, володіючи необхідними знаннями, зможете зробити чат.

Ключова особливість чату в тому, що його вміст оновлюється автоматично. Звідси і всі труднощі.

Для початку розберемо з Вами структуру таблиці у базі даних. Ось ті поля, які обов'язково знадобляться:

  • id- Унікальний ідентифікатор.
  • name- Ім'я, що залишило повідомлення. Тут також може бути, наприклад, user_id, що означає idкористувача з іншої таблиці.
  • message- Сам текст повідомлення.
  • date- Дата відправлення повідомлення.

Безумовно, це лише приклад. Ви можете додавати ще багато інших полів, тим самим, розширюючи можливості Вашого чату.

Тепер потрібно вивести HTML-код:













Ім'я Повідомлення Дата
Ім'я Повідомлення Дата




У цьому коді знову ж таки все як приклад. Можна все сміливо змінювати, але принцип має бути тим самим: є місце, де виводяться повідомлення, причому вони виводяться в однаковому вигляді. Разом із полем, де виводяться повідомлення, є текстове поле та кнопка " Відправити".

Обов'язково для блоку chatпоставте фіксовану висоту, щоб при додаванні нових повідомлень, у вас цей блок не виростав, також поставте смугу прокручування в нього, щоб можна було переглянути всі повідомлення. Все це робиться за допомогою CSS.

Тепер займемося JavaScript:

І наостанок, PHP-код(додавання нових повідомлень):

/* Отримуємо дані, отримані з JavaScript */
$message = $_POST["message"];
$name = $_POST["name"];
$date = date(); // Дізнаємося поточний час і дату
/* Тут додаємо в таблицю новий запис */
?>

І останній файл, який потрібно - це отримання всіх повідомлень з таблиці:

/* Витягуємо всі записи з таблиці */
/* Отримуємо двовимірний масив з отриманих даних */
/* Перетворимо масив у json-формат і повертаємо його в JavaScript, де він вже буде виводитися */
?>

Все, коло замкнулося, і чат заробив. Як бачите, зробити чат досить складноі потрібно мати великий багаж знань. Але я сподіваюся, що ця стаття дуже полегшить Вам це завдання. Абсолютно будь-який чат, хоч би який він складний був, заснований на принципах, описаних у цій статті, тому сміливо можете його використовувати як каркас.

Останнє оновлення: 31.10.2015

Минулого разу ми визначили контролер і модель, а тепер створимо решту чату. Спочатку визначимо уявлення.

Код головного уявлення Index.cshtmlбуде виглядати так:

@model AjaxChat.Models.ChatModel @( Layout = null; ) Чат на Ajax та JQuery@Styles.Render("~/Content/Site.css")

Введіть ім'я:
@Ajax.ActionLink("Login", "Index", New (user = ""), New AjaxOptions (UpdateTargetId = "container", OnFailure = "LoginOnFailure", OnSuccess = "LoginOnSuccess"), New ( @id = "Login ", @style = "visibility:hidden;" )) @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/scripts/jquery.unobtrusive-ajax.min.js") @Scripts. Render("~/Scripts/chat.js")

Це уявлення без майстер-сторінки. Елемент div з id="Username" відображатиме нік користувача. Блок з id="LastRefresh призначений для відображення часу останнього оновленнячату, а div c id="Error" - для виведення помилок, які можуть виникнути.

І для власне логіну у нас є текстове поле та кнопка. Однак при введенні ніка та натисканні на кнопку дані відразу не будуть передаватися на сервер, оскільки це не форма. Реальна відправка даних на сервер буде відбуватися за допомогою ajax-посилання, яке матиме id = "LoginButton":

@Ajax.ActionLink("Login", "Index", New (user = ""), New AjaxOptions (UpdateTargetId = "container", OnFailure = "LoginOnFailure", OnSuccess = "LoginOnSuccess"), New ( @id = "Login ", @style = "visibility:hidden;"))

При натисканні на посилання відбувається оновлення блоку з id="container" . За рахунок цього буде відбуватися часткове оновлення поточної сторінки за допомогою ajax, а не перезавантаження сторінки. Але самі ми на посилання натискати не будемо. Ми її навіть бачити не будемо, тому що у неї встановлений стиль "visibility: hidden;"

Натискання буде відбуватися автоматично в файлі, що з'являється в поданні chat.js:

$(document).ready(function() ( // логін $("#btnLogin").click(function() ( var nickName = $("#txtUserName").val(); if (nickName) ( // формуємо посилання з параметрами, за якими йде звернення var href = "/Home?user=" + encodeURIComponent(nickName); href = href + "&logOn=true"; $("#LoginButton").attr("href", href ).click(); //установка поля з ником користувача $("#Username").text(nickName); ) )); )); //при успішному вході завантажуємо повідомлення function LoginOnSuccess(result) ( Scroll(); ShowLastRefresh(); //кожні п'ять секунд оновлюємо чат setTimeout("Refresh();", 5000); //надсилання повідомлень за натисканням Enter $(" #txtMessage").keydown(function (e) ( if (e.keyCode == 13) ( e.preventDefault(); $("#btnMessage").click(); ) )); //установка обробника натискання кнопки для відправки повідомлень $("#btnMessage"). href = "/Home?user=" + encodeURIComponent($("#Username").text()); href = href + "&chatMessage=" + encodeURIComponent(text); $("#ActionLink").attr(" href", href).click(); ) )); //обробник кнопки виходу з чату $("#btnLogOff").click(function () ( //звертаємося до методу Index і передаємо параметр "logOff" var href = "/Home?user=" + encodeURIComponent($("#Username").text()); href = href + "&logOff=true"; $("#ActionLink").attr("href", href). click(); document.location.href = "Home"; )); ) //при помилці відображаємо повідомлення про помилку при логіні function LoginOnFailure(result) ( $("#Username").val(""); $("#Error").text(result.responseText); setTimeout("$ ("#Error").empty();", 2000); ) // кожні п'ять секунд оновлюємо поле чату function Refresh() ( var href = "/Home?user=" + encodeURIComponent($("#Username") $("#ActionLink").attr("href", href).click(); setTimeout("Refresh();", 5000); ) //Відображаємо повідомлення про помилку function ) ( $("#Error").text(result.responseText); setTimeout("$("#Error").empty();", 2000); ) // при успішному отриманні відповіді з сервера function ChatOnSuccess(result ) ( Scroll(); ShowLastRefresh(); ) //скролл до низу вікна function Scroll() ( var win = $("#Messages"); var height = win.scrollHeight; win.scrollTop(height); ) // відображення часу останнього оновлення чату function ShowLastRefresh() ( var dt = new Date(); var time = dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds(); $(" #LastRefresh").text("Останнє оновлення було в "+ time); )

Щоб надіслати дані по логіну та натиснути на посилання, в обробнику натискання ми прописуємо наступні рядки:

// формуємо посилання з параметрами, яким йде звернення var href = "/Home?user=" + encodeURIComponent(nickName); href = href + "&logOn=true"; // автоклік за ajax-посиланням $("#LoginButton").attr("href", href).click();

Оскільки в запиті до сервера передається параметр logOn=true, то метод Index під час обробки цього запиту надсилатиме клієнту часткове подання ChatRoom: return PartialView("ChatRoom", chatModel); . Створимо це уявлення:

@( Html.RenderPartial("History", Model); )
@Ajax.ActionLink("ActionLink", "Index", новий (user = "", logOn = "", logOff = "", chatMessage = "" ), новий AjaxOptions ( UpdateTargetId = "RefreshArea", OnSuccess = "ChatOnSuccess" , OnFailure = "ChatOnFailure" ), new ( @id = "ActionLink", @style = "visibility:hidden;" ))

Це часткове уявлення, типізоване моделлю ChatModel, яка передається з методу Index. Воно містить поля для введення та надсилання повідомлень, а також кнопку виходу з чату.

Крім того, тут є блок div id="RefreshArea", призначений безпосередньо для виведення повідомлень та користувачів. Для рендерингу цієї інформації у ньому йде звернення до часткового подання History, що ми зараз створимо. І також тут є невидиме ajax-посилання, що оновлює блок div id="RefreshArea" :

@Ajax.ActionLink("ActionLink", "Index", новий (user = "", logOn = "", logOff = "", chatMessage = "" ), новий AjaxOptions ( UpdateTargetId = "RefreshArea", OnSuccess = "ChatOnSuccess" , OnFailure = "ChatOnFailure" ), new ( @id = "ActionLink", @style = "visibility:hidden;" ))

У розглянутому файлі javacript при вдалому логіні викликається функція LoginOnSuccess , яка у свою чергу викликає функцію Refresh() :

Function Refresh() ( var href = "/Home?user=" + encodeURIComponent($("#Username").text()); $("#ActionLink").attr("href", href).click( );setTimeout("Refresh();", 5000);

Ця функція знову ж таки формує рядок запиту з параметрами для ajax-посилання та здійснює автоклік на неї. В результаті блок div id="RefreshArea" оновлюватиметься новими даними кожні п'ять секунд.

Подібна дія відбуватиметься також і при натисканні на кнопку надсилання повідомлення в чат:

Var href = "/Home?user=" + encodeURIComponent($("#Username").text()); href = href + "&chatMessage=" + encodeURIComponent(text); $("#ActionLink").attr("href", href).click();

І оскільки в обох випадках при передачі параметрів метод Index контролера параметри logOn і logOff будуть не встановлені, то метод Index у відповідь повертатиме часткове подання History.cshtml: return PartialView("History", chatModel);

Тепер створимо саме часткове уявлення History.cshtml:

@using AjaxChat.Models @model ChatModel

У чаті онлайн: @Model.Users.Count

@foreach (ChatUser user in Model.Users) ( )
@foreach (ChatMessage msg in Model.Messages) (

@msg.Date
@if (msg.User! = null) ( @(msg.User.Name + ":")@msg.Text ) else ( @msg.Text }

}

Наприкінці можна ще якось стилізувати додаток. У результаті має бути приблизно так. При запуску ми побачимо поле логіну:

 

 

Це цікаво: