Создаем чат для сайта: HTML, JS, PHP и AJAX
Когда обычных комментариев становится недостаточно, приходит время создать чат.
С помощью чата пользователи общаются друг с другом, повышая интерес к сайту. Это важный элемент для вебинарных площадок, порталов со службой поддержки и страниц, где необходимо более живое, нефорумное общение. Гайд поможет на практике скомбинировать знания по HTML, JS, PHP и AJAX и создать готовый продукт.
Если знаний ещё недостаточно, обратите внимание на курс «Веб-разработчик c нуля до PRO».
Пишет о программировании, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Каким должен быть чат
Удобство для пользователей превыше всего. Позаботьтесь, чтобы чат соответствовал современным требованиям:
Каркас чата на HTML
В первую очередь создаём форму отправки и контейнер для отображения сообщений:
Задаём стили
Первый этап пройден:
В первую очередь уделим внимание главным функциям чата, а после доработаем внешний вид.
Основная часть чата
на JS + PHP
Сообщения будут отправляться и загружаться с помощью AJAX. На JavaScript пишем функции работы с интерфейсом и связи с серверной частью, а на PHP — методы обработки полученных данных и взаимодействия с базой данных.
Создаем переменные на JS
Создаем функцию для запросов
Она получает переменную act, в которой хранится одно из трёх значений: auth (авторизация), load (загрузка) и send (отправка). От них зависит, какая информация будет передана в PHP-файл.
Создаём функцию обновления чата
И укажем для нашей функции интервал выполнения:
После отлавливается событие отправки формы — это поможет отказаться от обновления страницы:
Теперь займёмся самим обработчиком. В первую очередь с помощью функции session_start () запускается сессия, затем подключается база данных:
Создаём функцию авторизации
Создаём функцию загрузки
Создаём функцию отправки сообщений
В функции уже присутствует несложная валидация, но можно добавить и другие меры защиты от инъекций и спама:
Теперь, когда все функции готовы, пропишем их вызов.
Вызываем функции
Со стороны фронтенда мы ещё не реализовали авторизацию, но уже можем проверить чат, потому что в самом начале данные администратора были занесены в сессию. Вот как это выглядит:
Теперь, когда чат работает, пора добавить авторизацию. Для этого можно создать отдельную форму во фронте, но можно обойтись и модальными окнами. В функции send_request () дополним отправку запроса:
Вот как это выглядит:
Дополнительные функции
Минимальные возможности чата у нас есть, и продукт можно запускать в релиз, но добавим ещё несколько полезных штук.
Смайлики
Создадим свой набор смайликов чата. Работать это будет так:
Для начала добавим контейнер со смайликами и кнопку для его открытия:
Добавим скрипт для загрузки смайликов и открытия меню с ними:
А теперь и функцию добавления смайлика в поле:
После этого укажем, когда вызываются функции:
Приступим к загрузке смайликов и их преобразованию на PHP:
Эта функция сканирует папку со смайликами, а потом проверяет расширение файлов. Она очень удобна, потому что отображает в формате PNG все смайлики, которые мы добавили.
Чтобы вызвать её, добавим ещё один case в функцию switch () в конце обработчика:
Теперь с помощью регулярных выражений можно заменять код смайлика на изображение:
Вызывается эта функция при загрузке сообщений:
Вот как это выглядит:
Ответ на сообщения
Чтобы добавить возможность отвечать кому-то конкретному, изменим функцию addEmoji (). При нажатии на ник собеседника будет меняться текст в поле ввода.
Для этого в load () изменим формат сообщений, добавив span к нику:
Пишем саму функцию:
И вызываем функцию:
Заключение
Одной статьи недостаточно, чтобы охватить все возможности PHP и JS для разработки чатов. С помощью этих языков легко добавить:
Научиться делать подобные вещи самому не просто. Придётся перерыть гору литературы или искать готовые решения. На нашем курсе вы получите практические знания, которые помогут разобраться во всех деталях и делать более сложные проекты.
Простой чат на JavaScript и PHP
Как же работает этот скрипт? Сначала, подключается к базе данных. После подключения, смотрим, что запришивает клиент.
Если он запрашивает сообщения, то генерируем сколько сообщений не хватает клиенту. Затем, запрашиваем в безе все необходимые сообщения, добавляем их в массив, генерируем JSON и посылаем все это дело клиенту.
Теперь, у нас есть основа для чата. Все, что нам осталось сделать, так это обновление чата на стороне клиента и добавление новых сообщений в чат. Для всего этого, мы будем использовать Ajax запросы.
Давайте, создадим в файле index.php скрипт для обработки и добавления сообщений.
Добавим между тегов head >. head > наш Javascript:
Разберем этот скрипт…
Строка (3). Если в куках есть имя пользователя, то заполняем форму с именем. Для чего это сделано? Если пользователь обновил страничку с чатом или зашел заново на страницу с чатом, то ему не придется вводить свое имя заново.
Строка (7). Функция обновления чата. Чат обновляется не полностью, а присылаются только те сообщения, которых нет в чате.
Строка (9). Генерируем Ajax запрос. Для чего нужно отправлять лишнюю переменную «t=»+(new Date).getTime()? Если не отправить, то некоторые браузеры кэшируют одинаковые Ajax запросы. А нам это не нужно! т.к. не смогут обновляться сообщения. Функция (new Date).getTime() возвращает время в миллисекундах. Таким образом, браузер не кэширует запрос, т.к. при каждой отправке, генерируется разная строка.
Строка (16). Почему именно больше двух символов? Да потому что если все сообщения в чате есть, то сервер присылает не пустую строку, а «[]». т.к. ответ генерируется в JSON.
Строка (37). Запрос новых сообщений раз в две секунды. Мне очень понравился плагин jQuery Timers. С помощью него можно очень гибко сделать повторение определенных действий любое количество раз.
В общем-то, и всё. Вот и готов наш чат. Проверку имени на валидность и смайлы оставляю для домашнего задания.
Как я писал свой чат
Привет, Хабр!
В статье я написал, о том как разрабатывал чат. О его архитектуре и о технических решениях принятых в ходе его разработки.
Исходный код проекта: GitHub
Итак, понеслась.
Модель
Данные и их синхронизация.
Запись и воспроизведение звука.
Данные и их синхронизация.
В начале когда я писал первую версию, я сразу же написал асинхронную версию клиента и сервера. Но, почему-то, напрочь забыл про то, что данные нужно синхронизировать. И так-как серьезной нагрузки чат никогда не испытывал, то я понял это только после введения в чат передачи файлов. После этого сразу все вспомнилось и везде было вставлено куча локов. Что разумеется не было лучшим решением. Если сказать точнее, то это было всего лишь чуть лучше, чем программа без синхронизации.
Сейчас же на клиенте и на сервере используется единый механизм доступа к данным. Блокируется полностью модель. Должен сказать что для сервера это не самое удачное решение.
Идея достаточно простая: есть контекст, который приватным статическим полем содержит модель. В конструкторе он, вызывает Monitor.Enter. На саму модель, либо на отдельный объект синхронизации. Так же контекст реализует интерфейс IDisposable и в методе Dispose он эту эту модель освобождает, вызывая метод Monitor.Exit.
Обобщенный класс используемый как для сервера, так и для клиента. В примере модель содержится не в самом контексте а в классе его создающем.
В результате, для доступа к данным хочешь-не хочешь их нужно блокировать, и уже не задумываешься о синхронизации. Главное не забывать использовать конструкцию using. Для сервера это не является лучшим решением т.к. половина команд работают с 2умя пользователями максимум, а блокируются в результате — все.
Контекст в программе может создавать только одна сущность (ServerModel — (неожиданно) для сервера, и ClientModel — для клиента). Она представляет собой класс содержащий статическую приватную модель (саму себя), API а также клиентское соединение и пир — для клиентской модели или сервер для серверной. (API, клиент и т.д. содержатся как статические поля). Также клиентская модель, в отличии от серверной, содержит еще и события. На которые будет подписан пользовательский интерфейс. В общем эти классы выступают как основные для доступа к чему либо.
В качестве примера приведу серверную модель (она поменьше). Обратить внимание следует на метод Get() создающий контекст.
API в данном случае это логика чата. Она представляет собой класс хранящий в себе команды которые могут выполнятся на нашей стороне, и набор методов которые отправляют команды другой стороне (Клиенту, если рассматриваем себя со стороны сервера. Для клиента это сервер или другой пир). В методах содержатся наиболее сложные команды, либо просто часто используемые.
Работает вся эта система следующим образом: как только клиент или сервер принимает пакет данных, он передает его на анализ в API. (У сервера принимают сообщения его соединения, а они в свою очередь дергают один метод у сервера, о том что данные приняты). API просто считывает первые два байта сообщения и ищет у себя в словаре команду с нужным id, и возвращает ее. Или пустую команду, которая ничего не делает, если такого id нет. Дальше команде передается полученный пакет, и id приславшего его соединения и она выполняется.
Также API имеет свой интерфейс, изначально его не было. Появился после того как я решил написать другую его реализацию, предполагалось что это будет защищенное API. Но потом мне это просто стало не интересно, и я не на долго забросил проект. Месяца на два. После возвращения к нему мне уже не хотелось все это делать, и я занялся реализацией P2P.
Клиент, кстати, умеет сам выбирать API, который использует сервер, и если такового не имеется он отсоединяется от сервера и говорит что не поддерживает серверный API. Это реализовано достаточно просто — после того как сервер принял соединение он сразу же отправляет строку с названием своего API, а клиент собственно ожидает эту строку и устанавливает нужный интерфейс. Ну или не устанавливает, если такой не поддерживает. После этого действия уже идет апишный запрос регистрации пользователя на сервере.
Метод сервера обрабатывающего принятые пакеты:
Полный код класса API (в данном случае — серверного):
Каждая команда реализует интерфейс команды. Для сервера IServerAPICommand, для клиента IClientAPICommand, на данном этапе их можно было бы свести к 1 интерфейсу, но мне этого делать почему то не хочется. Также она содержит свой Id и данные необходимые для ее выполнения, описывающееся классом MessageContent. Впрочем команде могут быть и не нужны данные. И она сама ответственна за то, что бы десериализовать набор байт в экземпляр класса.
Пример команды. В данному случае это команда добавления файла в комнату:
Запись и воспроизведение звука.
Добавлением голосового чата занялся недавно, возможно во время публикации он все еще будет в демо версии. Но уже успел повозится с воспроизведением и записью звука.
Первым вариантом были WinApi функции waveIn* waveOut*. Это был самый простой вариант, поэтому начал с него. Но с ними не сложилось, т.к. на версии framework’a 3.5 неадекватно работал маршалинг на платформе x64 и при запуске приложение просто падало без каких либо исключений. При сборке под х86 все было нормально.
Дальше была попытка подключить DirectSound, но у него был найден свой баг с способом оповещения о завершении проигрывания куска данных. После гугления на эту тему выяснилось, что Mircosoft давно забросили DirectSound и работают с XAudio2. К тому же его использование привело бы к необходимости компиляции 2ух версий х86 и х64.
Так как мне не хотелось самому писать обертку для XAudio2, то я вспомнил про OpenAL. Для которого к тому же есть обертка (OpenTK), еще и с открытым исходным кодом. Из OpenTK был аккуратно вырезан только сама аудио библиотека. Которая сейчас и работает в программе.
Так как мне приходилось работать OpenGL ES 2, то и с OpenAL я подружился сразу. Особенное если учесть что по нему на официальном сайте OpenTK есть примеры.
Для записи данных я использую достаточно простую схему, из примера. При включении записи, запускается таймер, период срабатывания которого настраивается на время, за которое буфер должен заполнится на половину. После чего данные из него считываются и отправляются командой ClientPlayVoiceCommand всем кто может слушать нас.
Изначально чат представлял собой одну главное комнату, где находились все пользователи. Из протоколов передачи данных использовался только TCP. Так — как он уже предоставляет надежность передачи данных оставалось только разбить его непрерывный поток на сообщения.
Это было сделано просто добавлением размера сообщения в его начало.
То есть пакет представляет из себя следующее:
Первые 4 байта — размер сообщения.
5-6 байт — идентификатор команды.
Остальные данные это сериализованный MessageContent.
Далее на одном форуме мне предложили ввести передачу файлов и голосовую связь. С файлами я справился почти сразу, правда в первой версии файлы передавались через сервер, что было вообще ужасно. После этого я задумался над тем, что хорошо было бы передавать их на прямую. Как вы знаете с проблемой NAT, это сделать не так то и просто.
Я долго возился и пытался реализовать обход NAT используя TCP, тогда бы не пришлось парится по поводу ненадежности UDP. С ним так ничего и не получилось. После чего было решено использовать UDP и технологию UDP hole punching.
А для начала надо было решить проблемы надежности. Как обычно бывает, я начал трудится над своим протоколом поверх UDP обеспечивающим мне надежную доставку сообщений. И он все таки у меня получился, но работал только локально. При его тестировании в реальных условиях он, видимо, настолько нагружал сеть, что у меня полностью зависал компьютер.
После этого я начал искать уже реализованные библиотеки и наткнулся на сатью на Хабре, где аналогичная проблема была решена с помощью Lidgren.Network. Она и была выбрана.
Обход NAT реализован на уровне API. Схема простая, нужно всего лишь, что бы пиры узнали реальные адреса, по которым их видит сервер. После этого один пир должен кинуть сообщение другому. Это сообщение возможно не дойдет, но создаст правило на роутере, что сообщения от того адреса, по которому оно было отправлено нужно доставлять именно этому компьютеру. После этого с помощью сервера другой пир узнает, что ему уже можно подключатся и, собственно, подключается.
Черными стрелками обозначены отправки команд. Красным инициализации Lidgren.Network соединений.
Весь этот алгоритм спрятан в AsyncPeer, и достаточно вызвать метод SendMessage, и если клиент не подключен, он сам подключится, и отправит сообщение. Либо сразу отправит, если уже подключен.
Команды голосовой связи инициируют соединение немного иначе. При создании голосовой комнаты сервер создает в комнате карту подключений. В которой записано куда должен подключится каждый пользователь в комнате. А команды воспроизведения голоса отправляются с помощью метода AsyncPeer.SendMessageIfConnected, который просто выкидывает сообщение, если соединения нет.
Пользовательский интерфейс.
Напоследок немного об интерфейсе программы.
Он разработан с помощью WPF и паттерна MVVM. Очень гибкая технология, правда в версии 3.5 немного сыровата, но тем не менее позволяет обойти сыроватые места. Как на пример некоторые свойства Command все еще не зависимые, и для них пришлось написать обертку CommandReference.
Еще приходилось вместо оберток использовать AttachedProperty, которые в свою очередь изменяют нужные.
Для оповещения интерфейса об изменениях было решено использовать событийную модель, при этому в событиях передается вся необходимая информация, чтобы отобразить изменения.
В прочем, об интерфейсах написать больше нечего, WPF как WPF.
Как сделать чат
Думаю, что каждый из Вас знает, что такое чат. И очень часто на сайтах можно встретить либо маленькие чаты, либо достаточно большие и сложные. В этой статье я опишу принцип создания чата. Обратите внимание, что в этой статье не будет готового кода «скопировал-вставил«, а только алгоритм, с помощью которого Вы, обладая необходимыми знаниями, сможете сделать чат.
Ключевая особенность чата в том, что его содержимое обновляется автоматически. Отсюда и возникают все трудности.
Для начала разберём с Вами структуру таблицы в базе данных. Вот те поля, которые обязательно потребуются:
Безусловно, это только пример. Вы можете добавлять ещё массу других полей, тем самым, расширяя возможности Вашего чата.
Теперь необходимо вывести HTML-код:
В данном коде опять же всё как пример. Можно всё смело менять, но принцип должен быть тем же: есть место, где выводятся сообщения, причём они выводятся в одинаковом виде. Вместе с полем, где выводятся сообщения, есть текстовое поле и кнопка «Отправить«.
Обязательно для блока chat поставьте фиксированную высоту, чтобы при добавлении новых сообщений, у Вас этот блок не вырастал, также поставьте полосу прокрутки у него, чтобы можно было просмотреть все сообщения. Всё это делается с помощью CSS.
Теперь займёмся JavaScript:
И, наконец, PHP-код (добавление новых сообщений):
Всё, круг замкнулся, и чат заработал. Как видите, сделать чат достаточно сложно и нужно обладать большим багажом знаний. Но я надеюсь, что данная статья здорово облегчит Вам эту задачу. Абсолютно любой чат, какой бы он сложный ни был, основан на принципах, описанных в данной статье, поэтому смело можете его использовать как каркас.
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 25 ):
Спасибо за статью, Михаил! Но ведь можно сделать и без применения js?
Можно, с применением frame. Но это очень плохой вариант в том плане, что, во-первых, будет «моргать» экран, поскольку обновляется целиком весь блок, особенно это будет заметно на медленных компьютерах. Также очень сильно ограничена функциональность и многое нельзя будет сделать.
Можно взять готовый скрипт чата. Минусов масса, но если ничего не знаете, то это единственный вариант.
Михаил а как сделать так чтоб аякс запрос, проверял есть ли новые сообщения, если есть то уже подгружает, а если нет то нет. как вот сделать эту проверку? Сама структура запроса не ясна. пожалуйста обьясните.
Отправлять вместе с запросом id последнего сообщения, например. Если новое появилось, то возвращать результат.
Если беспокоитесь о безопасности, то можете и так сделать. Как альтернатива, можете передавать не id, а время последнего обновления. Тогда выводить только сообщения, отправленные позже этого времени.
Можно сделать асинхронную подгрузку сообщений если не беспокоетесь о нагрузке
Я сделал чат по такому же принципу, только я не знал как обновлять и узнал здесь. Спасибо.
Михаил, а как сделать так, чтобы при обновлении страницы все сообщения из окна чата исчезали? Т.е. каждый новый пользователь не видел сообщений старых. И если это вообще возможно, то где хранить сообщения в БД или в файлах… Спасибо
Можно хранить в cookie дату первого посещения чата и выводить сообщения только, отправленные позже этого времени.
у меня вопрос) я не разбирал код честно говоря, просмотрел поверхностно) но как быть в случае когда нужно показывать 100 сообщений, тогда контент страницы требует прокрутку) и вид вовсе не компактный, как решить эту проблему? просто не хочу курить форумы))
Через CSS у блока можно поставить максимальную высоту и прокрутку.
спасибо) просто не сталкивался с прокруткой) обязательно попробую)
Михаил, вы пишите статьи для людей или для поисковиков?
В первую очередь, для людей. Для поисковиков только ставлю.
Михаил, спасибо за статью. Вопрос: мне нужно установить, уже готовый чат Mibew Messenger.Все понятно, но там нужно создать БД MySQL и БД пользователя, где это создавать и как? управление сайта через самописную cms. В примере БД создаются в phpMyAdmin.
Для создания пользователя и БД используйте все тот же phpMyAdmin
Пишем чат на Python и Django
Добрый день, друзья. В преддверии старта курса «Web-разработчик на Python» традиционно делимся с вами полезным переводом.
Вы видите перед собой руководство, которое расскажет, как создать приложение-чат на Python, Django и React.
В отличие от других руководств, я не использую Python и Django для WebSocket-соединений. Несмотря на то, что это звучит круто с технической точки зрения, работает это довольно вяло и само по себе затратно, особенно, если у вас приличное количество пользователей. Такие языки, как C++, Go и Elixir намного лучше справляются с ядром чата.
В этом руководстве мы будем использовать Stream, API для чата, которое позаботится о WebSocket- соединениях и других тяжелых аспектах, используя Go, Raft и RocksDB.
Шаг 1: Интерфейс демо-чата на React
Прежде чем мы начнем думать о Python-части, давайте развернем простенький интерфейс на React, чтобы у нас было что-то красивое и визуальное:
Замените код в src/App.js на следующий:
Шаг 2: Установка Django/Python (пропустите этот шаг, если у вас уже есть все необходимое)
Убедитесь, что у вас есть Python 3.7 и он запущен:
Если не сработало, попробуйте следующий код:
Теперь, когда вы в своей виртуальной среде, вы должны увидеть python 3 при запуске:
Чтобы создать новый проект на Django, используйте следующий код:
И запустите приложение:
Шаг 3: Авторизация пользователей
Следующий шаг – настройка авторизации пользователей в Django.
Перейдите на http://localhost:8000/admin/ и войдите. Вуаля!
Вы увидите вкладку администратора на подобие той, что ниже:
Шаг 4: Django Rest Framework
Один из моих любимых пакетов для интеграции React с Django – это Django Rest Framework. Чтобы все заработало, нужно создать конечные точки для:
Чтобы установить Djoser, используйте следующее:
После этого отредактируйте urls.py и измените содержимое файла следующим образом:
По завершении, отредактируйте settings.py и внесите изменения:
Для получения дополнительной информации о конечных точках API, которые предоставляет Djoser, посмотрите следующее:
Теперь давайте продолжим и протестируем конечную точку регистрации:
Шаг 5: Генерация токенов для доступа к Stream-серверу чата
Теперь нам нужно настроить представления Djoser для генерации токенов Stream. Итак, начнем.
Давайте немного упорядочим наши файлы и создадим папку приложения чата в нашем проекте (убедитесь, что вы находитесь в правильном каталоге):
Создайте кастомный сериализатор в auth/serializers.py с помощью следующей логики:
И последнее, используйте кастомный сериализатор, чтобы обновить файл settings.py :
Чтобы убедиться, что он работает, попадите в конечную точку с помощью POST-запроса:
Шаг 6: Интеграция авторизации в React
По очевидным причинам, добавление авторизации к фронтенду – это важный шаг. В нашем случае это особенно полезно, поскольку мы можем извлечь токен пользователя из API (которое работает на Python) и динамически использовать его при отправке сообщений.
Во-первых, установите CORS – пакет промежуточного программного обеспечения для Django:
И наконец добавьте следующее к вашему файлу settings.py :
Следующий шаг потребует внесения нескольких изменений в ваш интерфейс. Для начала вам нужно будет убедиться, что у вас есть все зависимости, установленные через yarn:
Далее создайте следующие файлы в директории src/ :
App.js
AuthedRoute.js
UnauthedRoute.js
withSession.js
Login.js
Chat.js
Обязательно замените YOUR_STREAM_APP_ID на валидный ID приложения Stream, который можно найти на дашборде.
Перезапустите приложение на фронтенде и вы увидите авторизацию! Введите адрес электронной почты и пароль, токен будет запрошен и сохранен в локальном хранилище.
Шаг 7: Отправка сообщений с сервера Python
Если вы внезапно захотите создать API чата с использованием вашего бэкенда на Python, есть специальная команда, которую можно использовать.
Убедитесь, что установленные приложения выглядят следующим образом в settings.py :
Далее создайте каталог chat/management/commands. В этот каталог добавьте файл с именем broadcast.py со следующим содержанием:
Вы можете попробовать отправить сообщение в чат следующим образом:
И вы увидите такой отклик:
Последние мысли
Надеюсь, вам понравилось это руководство по созданию приложения-чата на Django, Python и React!
Для интерактивного тура по Stream Chat, пожалуйста, взгляните на наше руководство по созданию API на сайте Stream. Если вам нравится копаться в коде компонентов Stream Chat React, полную документацию вы можете найти здесь. Если вам захочется создать чат на Stream, мы рады предложить различные SDK для популярных языков и фреймворков до последней iOS (Swift).