ITVDN logo
Видеокурсы по
программированию

Доступ более чем к 7700 видеоурокам от $19.99

Подписка
ITVDN logo
Видеокурсы по
программированию

Доступ более чем к 7700 видеоурокам от $19.99

Подписка

Создания простого чата

Для начала создадим простой чат с помощью HTML&CSS и PHP&MySQL

Проектирование Базы Данных

  1. Переходим к phpMyAdmin.
  2. Создаем новую базу данных, называем “chatdb”.
  3. Создаем новую таблицу, называя “Posts”, включая в себя 4 столбца:
  • “id” тип колонки INT, автоматическое увеличение на 1 (задаем A_I в ячейку с флажком) основной ключ (index);
  • “nick” тип колонки VARCHAR и длина 100;
  • “post_text” тип колонки TEXT;
  • “post_dt” тип колонки DATETIME по умолчанию является CURRENT_TIMESTAMP.

Создание веб-сайта.

  1. Во-первых, создадим главную страницу. Список комментариев и отправка формы, используя кнопку. Всё будет находится в файле “index.php” .  Давайте создадим этот файл и напишем что-то вроде этого: 

<html>

<head>

head>

<body>

php

$mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

/* "127.0.0.1" is MySQL host name. In local servers (XAMPP, Ampps, etc.) it is 127.0.0.1. If you using a dedicated hosting, see it in admin panel. */

/* "root" and "" is login and password for DB's user. In local servers usually default DB user is "root" with empty password. */

/* "chatdb" is DB's name. */

/* Warning: in XAMPP you should manually run MySQL server (from xampp-control.exe) to get it work. */

$result = $mysqli->query("SELECT * FROM posts;");

?>

<style>

/* All CSS is very simplified. I provide it for example and no more.

 * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

 */

.content {

  display: table;

  width: 50%;

  min-width: 400px;

  height: 80%;

  /* Center horizontally and vertically */

  position: absolute;

  left: 0; right: 0;

  top: 0; bottom: 0;

  margin: auto;

  /* Design */

  border: 1px solid;

  background-color: silver;

  padding: 5px;

}

/* For mobile devices */

@media (max-width: 400px) {

  .content {

    width: 100%;

    min-width: 0;

    padding: 0px;

  }

}

style>

<div class="content">

<div id="comments" style="overflow-y: scroll; height: 100%;">

php

if ($result) {

  while ($post = $result->fetch_object()){

    $nick = $post->nick;

    $post_dt = $post->post_dt;

    $post_text = $post->post_text;

   

    echo "<b>$nickb> ($post_dt):<br>";

    echo "$post_text<br>";

    echo "<br>";

  }

  $result->close();

}

?>

div>

php

$mysqli->close();

?>

<form action="post.php" method="post" style="height: 0; display: table-row;">

  Nick:<br>

  <input type="text" name="nick" style="width: 100%;">input><br>

  <br>

  Text:<br>

  <textarea name="text" style="width: 100%;">textarea><br>

  <br>

  <input type="submit">input>

form>

div>

<script type="text/javascript">

    var divComments = document.getElementById('comments');

    divComments.scrollTop = divComments.scrollHeight;

script>

body>

html>

2. Дальше давайте создадим “post.php” файл и напишем такое: 

php

$nick = $_POST['nick'];

$post_text = $_POST['text'];

$mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

$nick = $mysqli->real_escape_string($nick);

$nick = htmlspecialchars($nick);

$post_text = $mysqli->real_escape_string($post_text);

$post_text = htmlspecialchars($post_text);

$mysqli->query("INSERT INTO posts (nick, post_text) VALUES ('$nick', '$post_text');");

$mysqli->close();

/* Redirect To Main Page */

header('Location: ' . $_SERVER['HTTP_REFERER']);

?>

3. Откроем ваш чат в любом продвинутом браузере. Вся работа: 

4. Напишите ник и текст, а потом нажмите на кнопку отправки. 

Когда отправили форму, сразу же происходит перенаправление формы главной страницы в “post.php”. “Post.php” моментально наполняет данными таблицу и перенаправляет на главную страницу. Также “post.php” содержит начальный XSS и SQL защищенный вход. Для упрощения не отправляем клиентам время с JS на “post_dt” на внесения данных, а указываем значение по умолчанию – CURRENT_TIMESTAMP, который предоставляет нынешнюю дату и время на сервер.

Когда количество комментариев больше, чем экран может вместить, то комментарии   переполнены в div, используется вертикальный скроллбар. Во время загрузки страницы JS автоматически опускает скроллбар вниз к недавнему комментарию.

Что тут не так?

Проблема номер 1. Новый непрочитанный комментарий от пользователя не загружается в базу данных автоматически, без ручной перезагрузки страницы.

Это очень, очень серьезная проблема для любого чата.

Как это исправить?

Очевидно, один из путей сделать это - использовать HTTP-запрос к фоновой работе автоматически (с помощью JS) и асинхронно, то есть это один из способов обеспечить выполнение AJAX в любой form.

Проблема номер 2. Также неправильно то, что кнопка отправки перезагружает страницу (перенаправляет на вторую страницу и следующим шагом возвращает назад).

При перезагрузке страницы сбрасывает “Nick” в  поле (также, как любые другие изменения, те, что сделали с пользователем)

Как это исправить?

Конечно, можно обеспечить выполнение обхода для сохранения изменений и перезагрузки на перезагружаемой странице. Но не эффективнее ли устранить причину, чем последствие? Можно только убрать перезагружаемую страницу и эта проблема будет решена автоматически.

Проблема номер 2.1. Видите ли что-то необычное тут?

Это слишком быстро?

Дело с чатом очень простое – загружаем только два маленьких текстовых параметра. Что делать, если нужно улучшить чат с помощью добавления присоединения, а конкретно - изображений и видео? Видео может иметь объем в размере нескольких мегабайт, что тогда в этом случае?

Давайте попробуем.  Давайте немного изменим “post.php”, после $mysql->query() добавив это: 

for ($i = 0; $i < 1000000000; $i++) { }

Старайтесь размещать какие-либо комментарии. Что мы видим? Нет, UI не остановилось (заморозилось), но браузер ждет до того, как закончится подключение:  

Да, если “post.php” вызывает какую-то необработанную ошибку, то чат исчезает, и пользователь видит пустое окно с сообщением о непонятной ошибке. Чтобы вернуться к чату, пользователю стоит нажать кнопку “Back” в браузере. И это проблема номер 2.2.

Давайте уберем петлю с “post.php” и исправим эти проблемы.

Реализация легкого AJAX в простой чат

Автоматическое обновление комментариев

Эта веб-страница без AJAX? Это веб-страница, которая полностью перезагружается.

Эта веб-страница c AJAX? Это веб-страница, что перезагружается частично.

Где же взять части этих страниц? Стоит разделить нашу страницу на части, в этом случае сервер генерирует страницу частично.

Страница будет состоять из двух частей – блок комментариев и другой контент страницы. Комментарии будут загружаться и перезагружаться отдельно от другой страницы.

Давайте сделаем первую часть, то есть блок комментариев.

Для начала создадим пустой файл, назовем “getcomment.php”.

Дальше переходим в “index.php” для того, чтобы вырезать комментарии и далее отделить его.
1. Вырезаем инициализированный блок MySQL с “index.php" 

php

$mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

/* "127.0.0.1" is MySQL host name. In local servers (XAMPP, Ampps, etc.) it is 127.0.0.1. If you using a dedicated hosting, see it in admin panel. */

/* "root" and "" is login and password for DB's user. In local servers usually default DB user is "root" with empty password. */

/* "chatdb" is DB's name. */

/* Warning: in XAMPP you should manually run MySQL server (from xampp-control.exe) to get it work. */

$result = $mysqli->query("SELECT * FROM posts;");

?>

вставляем в “getcomments.php”.

2. Следующее, вырежем контент div c комментариями с “index.php”:

php

if ($result) {

  while ($post = $result->fetch_object()){

    $nick = $post->nick;

    $post_dt = $post->post_dt;

    $post_text = $post->post_text;

   

    echo "<b>$nickb> ($post_dt):<br>";

    echo "$post_text<br>";

    echo "<br>";

  }

  $result->close();

}

?>

И вставим (добавим) в “getcomments.php” после инициализации MySQL.

3. Дальше, вырежем недалекий блок MySQL с “index.php”:

php

$mysqli->close();

?>

Вставим его в конец файла “getcomments.php”.

4. Наконец-то, убираем JS-скрипт, который опускает скролл в самый низ.

<script type="text/javascript">

var comments = document.getElementById('comments');

comments.scrollTop = comments.scrollHeight;

script>

Не переживай, это только временно.

5. Сделано. Теперь имеем что-то наподобие этого:

 <html>

<head>

head>

<body>

<style>

/* All CSS is very simplified. I provide it for example and no more.

 * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

 */

.content {

  display: table;

  width: 50%;

  min-width: 400px;

  height: 80%;

  /* Center horizontally and vertically */

  position: absolute;

  left: 0; right: 0;

  top: 0; bottom: 0;

  margin: auto;

  /* Design */

  border: 1px solid;

  background-color: silver;

  padding: 5px;

}

/* For mobile devices */

@media (max-width: 400px) {

  .content {

    width: 100%;

    min-width: 0;

    padding: 0px;

  }

}

style>

<div class="content">

<div id="comments" style="overflow-y: scroll; height: 100%;">

div>

<form action="post.php" method="post" style="height: 0; display: table-row;">

  Nick:<br>

  <input type="text" name="nick" style="width: 100%;">input><br>

  <br>

  Text:<br>

  <textarea name="text" style="width: 100%;">textarea><br>

  <br>

  <input value="Submit" type="submit">input>

form>

div>

body>

html>

getcomments.php:

 php

$mysqli = new mysqli("127.0.0.1", "root", "", "chatdb");

/* "127.0.0.1" is MySQL host name. In local servers (XAMPP, Ampps, etc.) it is 127.0.0.1. If you using a dedicated hosting, see it in admin panel. */

/* "root" and "" is login and password for DB's user. In local servers usually default DB user is "root" with empty password. */

/* "chatdb" is DB's name. */

/* Warning: in XAMPP you should manually run MySQL server (from xampp-control.exe) to get it work. */

$result = $mysqli->query("SELECT * FROM posts;");

?>

Вероятно, теперь наша страница разделена.

Давайте проверим её. Переходим http (точнее ССЫЛКА для локального сервера).

Дальше, переходим на главную страницу, http:///index.php

Это удивительно! Всё удачно получилось, разделив страницу на части за пару минут!

Не останавливаемся на этом. Теперь “glue” эти части с помощью AJAX. Как это сделать?

1. Для начала стоит создать пустой JS-скрипт на главной странице:

<script type="text/javascript">

alert('Test');

script>

Добавив это после тега div, перед закрывающимся тегом .

2. Сделаем HTTP GET запрос от JS к “getcommet.php”

Для этого используем XMLHtttpRequest (XHR) класс:

<script type="text/javascript">

var xhr = new XMLHttpRequest();

xhr.open('GET', '/getcomments.php', false);

xhr.send(null);

if (xhr.status == 200) {

  alert(xhr.responseText);

}

script>

Это работает, но не читает старые версии IE те, что не поддерживают такую инициализацию.

Для получения более кросс-браузерного пути переходим в

и добавляем это:

<script type="text/javascript">

function getXmlHttp(){

  var xmlhttp;

  try {

    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");

  } catch (e) {

    try {

      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

    } catch (E) {

      xmlhttp = false;

    }

  }

  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {

    xmlhttp = new XMLHttpRequest();

  }

  return xmlhttp;

};

script>

И главный скрипт (в конце)

<script type="text/javascript">

var xhr = getXmlHttp();

xhr.open('GET', '/getcomments.php', false);

xhr.send(null);

if (xhr.status == 200) {

  alert(xhr.responseText);

}

script>

Как видно, теперь JS получает контент со страницы “getcomments.php” и показывает это в предупреждении.

 

2.1. Вопрос: «Это на самом деле AJAX (Asynchronous Javascript And Xml)?»

Это AJAX, потому что запрос сервера отформатирован в HTML (который основан на XML).

Но действительно ли это AJAX, это асинхронно?

Проверим. Добавим эти уже знакомые строки в любое место между в “getcomments.php”:

for ($i = 0; $i < 1000000000; $i++) { }

Что теперь видно на загружаемой странице?

Вначале страница зависает, его замораживает UI (становится не реагирующим на нажатие левой/правой кнопки мыши):

Дальше Chrome показывает навязчивое всплывающие окно, сообщающее об удалении страницы:

Это не AJAX! Это JAX! Как его сделать асинхронным?

К счастью, ХHR также поддерживает асинхронный режим:

<script type="text/javascript">

var xhr = getXmlHttp();

xhr.open('GET', '/getcomments.php', true); /* true for asynchronous */

xhr.onreadystatechange = function() {

  if (xhr.readyState == 4) {

    if(xhr.status == 200) {

      alert(xhr.responseText);

    }

  }

};

xhr.send(null);

script>

В этом случае браузер не ждет ответа с главного потока пользовательского интерфейса, он запускает в другом (асинхронно) и вызываемым событием “onreadystatechange” в главном контексте UI. 

Теперь всё в порядке, страница полностью доступна, пока запрос запущен, и после ответа получит предупреждение.

for ($i = 0; $i < 1000000000; $i++) { }

И продолжаем работу.

3. Добавляем этот контент в div  вместо предупреждения. Заменить это:

alert(xhr.responseText); 

C этим:

var divComments = document.getElementById('comments');

divComments.innerHTML = xhr.responseText;

Возвращаем назад, клиент видит “glued” страницу с блоком комментариев.

4. Дальше следует установить интервал для автоматической проверки новых комментариев время от времени… и также восстановить удаленный сценарий автоматической прокрутки. 

<html>

<head>

<script type="text/javascript">

    function getXmlHttp() {

        var xmlhttp;

        try {

            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");

        } catch (e) {

            try {

                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

            } catch (E) {

                xmlhttp = false;

            }

        }

        if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {

            xmlhttp = new XMLHttpRequest();

        }

        return xmlhttp;

    };

script>

head>

<body>

<style>

/* All CSS is very simplified. I provide it for example and no more.

 * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

 */

.content {

  display: table;

  width: 50%;

  min-width: 400px;

  height: 80%;

  /* Center horizontally and vertically */

  position: absolute;

  left: 0; right: 0;

  top: 0; bottom: 0;

  margin: auto;

  /* Design */

  border: 1px solid;

  background-color: silver;

  padding: 5px;

}

/* For mobile devices */

@media (max-width: 400px) {

  .content {

    width: 100%;

    min-width: 0;

    padding: 0px;

  }

}

style>

<div class="content">

<div id="comments" style="overflow-y: scroll; height: 100%;">

div>

<form action="post.php" method="post" style="height: 0; display: table-row;">

  Nick:<br>

  <input type="text" name="nick" style="width: 100%;">input><br>

  <br>

  Text:<br>

  <textarea name="text" style="width: 100%;">textarea><br>

  <br>

  <input value="Submit" type="submit">input>

form>

div>

<script type="text/javascript">

    var divComments = document.getElementById('comments');

    function loadComments() {

        var xhr = getXmlHttp();

        xhr.open('GET', '/getcomments.php', true);

        xhr.onreadystatechange = function () {

            if (xhr.readyState == 4) {

                if (xhr.status == 200) {

                    if (xhr.responseText !== divComments.innerHTML) {

                        divComments.innerHTML = xhr.responseText;

                        divComments.scrollTop = divComments.scrollHeight;

                    }

                }

            }

        };

        xhr.send(null);

    };

    loadComments();

    setInterval(loadComments, 1000)

script>

body>

html>

Теперь проблема исправить это. Новые комментарии с другого пользовательского чата (другие вкладки браузеров, окон и экземпляров) получают каждые 1000 миллисекунды (1 секунду) автоматически.

Но отправка комментариев уже вызывает перезагрузку нашей страницы.

Отправка комментариев без перезагрузки

Как написано выше, XHR помогает отправлять HTTP GET-запросы без перезагрузки страницы и GUI заморозки (асинхронно).

Теперь отправляем HTTP-запрос асинхронно, но на этот раз POST запрос, а не GET.

И, естественно, XHR позволяет это. Используем метод send(). Для GET указываем null. Для POST устанавливаем запрос “body”.Также нужно добавить “Content-Type:application/x-www-from-urlencoded” в header  для того, чтобы разрешить серверу знать, какой формат использовать для отправки данных.

Заметка: если не знаете, что отправлять, то можно захватить регулярный запрос с помощью “Fiddler” или же любой другой HTTP-перехватчик и только просимулировать запрос. HTTP-перехватчик — это незаменимый инструмент для работы с HTTP/HTTPS. Это позволяет увидеть все headers и bodies по всем HTTP(S)-запросам, что отправляются в систему. Лучше использовать “Fiddler”, это бесплатное, современное и очень простое приложение, что может поддерживать HTTP/HTTPS и оба Win x86/x64.

1. Для начала создадим пустой JS скрипт в HTML. Разместить до самого

тега, потому что этот скрипт будет использован для отправки формы комментария (форма будет вызывать этот скрипт при отправке).2. В этом скрипте, реализуем функцию, что будет отправлять ник и комментарии в “post.php”

 <script type="text/javascript">

function postComment(nick, text) {

  var xhr = getXmlHttp();

  xhr.open('POST', '/post.php', true);

  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

  xhr.onreadystatechange = function() {

    if (xhr.readyState == 4) {

      if (xhr.status == 200) {

        /* it isn't required to add comment to DOM manually, it will done automatically on next refresh via AJAX */

      }

    }

  };

  xhr.send('nick=' + nick + '&text=' + text); /* joining the data in format simulates form */

};

script>

3. Следующие, перезагружая страницу при отправке: 

... onsubmit="return false;">

Также добавим вызов “postComment’s”:

action="post.php" method="post" style="height: 0; display: table-row;" onsubmit="postComment(this.nick.value, this.text.value); return false;">

4. Наконец, необязательно, но можно убрать “action” и “method” с формы:

 <form style="height: 0; display: table-row;" onsubmit="postComment(this.nick.value, this.text.value); return false;">

5. Результат:

<html>

<head>

<script type="text/javascript">

    function getXmlHttp() {

        var xmlhttp;

        try {

            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");

        } catch (e) {

            try {

                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

            } catch (E) {

                xmlhttp = false;

            }

        }

        if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {

            xmlhttp = new XMLHttpRequest();

        }

        return xmlhttp;

    };

script>

head>

<body>

<style>

/* All CSS is very simplified. I provide it for example and no more.

 * In Chrome it works tolerably, but in IE and Firefox it works very poorly.

 */

.content {

  display: table;

  width: 50%;

  min-width: 400px;

  height: 80%;

  /* Center horizontally and vertically */

  position: absolute;

  left: 0; right: 0;

  top: 0; bottom: 0;

  margin: auto;

  /* Design */

  border: 1px solid;

  background-color: silver;

  padding: 5px;

}

/* For mobile devices */

@media (max-width: 400px) {

  .content {

    width: 100%;

    min-width: 0;

    padding: 0px;

  }

}

style>

<div class="content">

<div id="comments" style="overflow-y: scroll; height: 100%;">

div>

<script type="text/javascript">

    function postComment(nick, text) {

        var xhr = getXmlHttp();

        xhr.open('POST', '/post.php', true);

        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

        xhr.onreadystatechange = function () {

            if (xhr.readyState == 4) {

                if (xhr.status == 200) {

                    /* it isn't required to add comment to DOM manually, it will done automatically on next refresh via AJAX */

                }

            }

        };

        xhr.send('nick=' + nick + '&text=' + text);

    };

script>

<form style="height: 0; display: table-row;" onsubmit="postComment(this.nick.value, this.text.value); return false;">

  Nick:<br>

  <input type="text" name="nick" style="width: 100%;">input><br>

  <br>

  Text:<br>

  <textarea name="text" style="width: 100%;">textarea><br>

  <br>

  <input value="Submit" type="submit">input>

form>

div>

<script type="text/javascript">

    var divComments = document.getElementById('comments');

    function loadComments() {

        var xhr = getXmlHttp();

        xhr.open('GET', '/getcomments.php', true);

        xhr.onreadystatechange = function () {

            if (xhr.readyState == 4) {

                if (xhr.status == 200) {

                    if (xhr.responseText !== divComments.innerHTML) {

                        divComments.innerHTML = xhr.responseText;

                        divComments.scrollTop = divComments.scrollHeight;

                    }

                }

            }

        };

        xhr.send(null);

    };

    loadComments();

    setInterval(loadComments, 1000)

script>

body>

html>

 Теперь простая реализация AJAX подошла к концу. Это ещё не конец, это только начало. Есть ещё достаточно всего для изучения и улучшения.

СТАТЬИ ПО СХОЖЕЙ ТЕМАТИКЕ
ВИДЕО КУРСЫ ПО СХОЖЕЙ ТЕМАТИКЕ

КОМЕНТАРИИ И ОБСУЖДЕНИЯ

ОЦЕНИТЕ ДАННЫЙ МАТЕРИАЛ

ПОДПИСКА НА ITVDN ВЫГОДА ДО 29.95$ НА ОБУЧЕНИЕ ПРЕСТИЖНЫМ ПРОФЕССИЯМ!

1 месяц19.99$
подписка

легкий старт в обучении

3 месяца49.99$
подписка

выгода от подписки до9.98$

6 месяцев89.99$
подписка

выгода от подписки до29.95$