| 
				
				Урок по созданию чата на jQuery (php+mysql)
				 |   |  
| Assasin | Дата: Среда, 28 Сентября 2011, 18:44 | Сообщение # 1 |  
 
web-coder 
Сейчас нет на сайте 
 
 | Доброго времени суток. Недавно меня в скайпе попросили сделать чат без перезагрузки страницы. Я принципиально отказался, т.к. у человека есть свободное время и если он захочет, то может сам найти инфу и написать такой чат. Но вот что бы такие вопросы не возникали в дальнейшем я решил написать небольшой урок по созданию чата с использованием библиотеки jQuery.   Вот такой чат получится в конечном итоге:    Подготовка   Нам понадобятся такие сторонние файлы:   - jquery (скачать) вся клиентская логика будет написана на нем   - apprise (скачать) для украшения всплывающих окошек   Все создаваемые файлы сохранять в кодировке utf-8 без BOM, т.к. json другие кодировки не любит.   Настройка сайта   Создадим файл .htaccess и впишем в него:   Code # Главный файл   DirectoryIndex index.html 
   # Кодировка страниц   AddDefaultCharset UTF-8     Клиентская часть   Создаем папку style и вставляем в нее скачаные файлы jquery.js, apprise.css, apprise.js. Также создаем в ней файлы style.css, script.js.   Открываем style.css и записываем каким будет выглядеть чат:   Code    /* Тело документа */   body {    margin: 0 auto;    padding: 0;    width: 800px;    background:rgba(0, 0, 0, 0.3);   }   /* Главный блок */   #stage {    height: 290px;    display: block;   }   /* Блок сообщений */   #message {    display: block;    float: left;    width: 590px;    height: 220px;    overflow: auto;    margin: 10px 0px 10px 10px;   }   /* Блок отображения юзверей */   #user {    display: block;    float: right;    width: 180px;    height: 220px;    margin: 10px 10px 10px 0px;   }   /* Закругляем красиво углы */   .corner {    background:#eee;    border:1px solid #fff;    box-shadow:0px 3px 7px #333;    -moz-box-shadow:0px 3px 7px #333;    -webkit-box-shadow:0px 3px 7px #333;    -moz-border-radius:4px;    -webkit-border-radius:4px;    border-radius:4px;    -khtml-border-radius:4px;   }   /* Отступ от границ */   .d {    padding: 10px;   }   /* Блок отправки сообщения */   #send_line {    margin: 0px 10px 10px 10px;    width: 780px;   }   /* стиль input отправки сообщения */   .msg {    width: 760px;    margin: 4px 0px 4px 10px;   }        Далее открываем файлик script.js и пишем следующий код, он будет отвечать за логику на стороне клиента:   Code    $(document).ready(function(){/* Как только загрузится документ, начинает работать код, который расположен внутри */    var name = null, // Будущее имя пользователя     id = 0; // id последнего сообщения    /* Начало работы, создаем запрос, который отсылает в скрипт core.php данные start=true методом POST ($_POST['start']=true) и принимаем от сервера данные в формате json */    $.ajax({     type: "POST",     url: "core.php",     data: "start=true",     dataType: 'json',     success: function(data) {      /* Если пришла ошибка от сервера, то показываем её пользователю и перезагружаем страницу */      if (data.err) {       if (data.err == 2) {        apprise('Невозможно найти БД', {}, function(r){         location.href = "index.html";        });       } else if (data.err == 1) {        apprise('База данных ушла в себя', {}, function(r){         location.href = "index.html";        });       }       return false;      }      /* Если ошибок нет и получен ответ = 0 то показываем пользователю всплывающее окно */      if (data.ans == 0) {       apprise('Введите логин', {'input': true}, function(login){ /* Если пользователь не ввел логин либо нажал "Отменить" перезагружаем страницу */        if (login == false) {         location.href = "index.html";        } else {/* Если ввел логин, то отправляем в файл core.php введеный логин и принимаем ответ опять же в формате json */         $.ajax({          type: "POST",          url: "core.php",          data: "name="+login,          dataType: 'json',          success: function(data) {           /* Если ответ = 0, то запоминаем имя пользователя и id последнего сообщения */           if (data.ans == 0) {            name = data.login;            id = data.id;           } else { /* Иначе выдаем ошибку и перезагружаем страницу */            apprise('Такой логин уже используется', function(r){                                 location.href = "index.html";            });           }          }         });        }       });      } else { /* Если получаем ответ != 0, то запоминаем имя пользователя и id последнего сообщения */       name = data.login;       id = data.id;      }     }    });    /* Функция которая возвращает сообщения и пользователей онлайн, обновляется каждые 2 сек (2000 милисек) */    update();    setInterval(update, "2000");        function update() {     /* Отправляем на сервер (файл core.php) данные update=1 и id последнего сообщения */     $.ajax({      type: "POST",      url: "core.php",      data: "update=1&id="+id,      dataType: 'json',      success: function(data) {       /* Проверяем наличие ошибок */       if (data.err) {        if (data.err == 2) {         apprise('Невозможно найти БД', {}, function(r){          location.href = "index.html";         });        } else if (data.err == 1) {         apprise('База данных ушла в себя', {}, function(r){          location.href = "index.html";         });        }        return false;       }       /* Обновляем список пользователей */       if (data.user != $("#user .d").html()) {        $("#user .d").html(data.user);       }       /* Добавляем новое сообщение на экран, прокручиваем скролл вниз и удаляем старые сообщения, оставивши последние 10 */       if (data.msg != "") {        id = data.id;        $('#message .d').append(data.msg);        $('#message').scrollTop($('#message')[0].scrollHeight);        var size = $("#message .d div").size();        if (size > 10) {         for (var i = 0; i < size-10; i++) {          $("#message .d div").eq(i).remove();         }        }       }      }     });     /* удаляем старые сообщения, оставивши последние 10. Данное действие дублируется, т.к. при загрузке страницы с чатом удаляются сообщения и при каждом новом полученом сообщении */     var size = $("#message .d div").size();     if (size > 10) {      for (var i = 0; i < size-10; i++) {       $("#message .d div").eq(i).remove();      }     }    }    /* Отслеживаем нажатие клавиш */    $('.msg').keydown(function(event){     if (event.which == 13) { /* Если нажато Enter, запоминаем сообщение и  */      var msg = $(this).val(),       then = $(this); /* Обращение на самого себя, т.е. на элемент, который имеет класс msg (в нашем случае это input) */      if (msg == "") { /* Если сообщение пустое, то прекращаем выполнять следующий код*/       return false;      }      /* Отправляем на сервер сообщение и если пришел положительный ответ (!= 0) то прокручиваем блок сообщений вниз и очищаем строку в которую вводим сообщение */      $.ajax({       type: "POST",       url: "core.php",       data: "msg="+msg,       dataType: 'json',       success: function(data) {        if (data.ans != 0) {         $('#message').scrollTop($('#message')[0].scrollHeight);         then.val("");        }       }      });     };    });   });     Ну и последнее это сам файл index.html, выходим с папки style и создаем его:   Code <!DOCTYPE html>   <html>       <head>           <title>Чат на jQquery</title>           <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">           <link rel="stylesheet" type="text/css" href="/style/style.css" />     <script type="text/javascript" src="/style/jquery-1.6.2.min.js"></script>     <script type="text/javascript" src="/style/apprise-1.5.full.js"></script>     <link rel="stylesheet" href="/style/apprise.css" type="text/css" />     <script type="text/javascript" src="/style/script.js"></script>       </head>       <body>           <div id="stage">      <div id="message" class="corner"><div class="d"></div></div>      <div id="user" class="corner"><div class="d"></div></div>      <div style="clear:both;"></div> <!-- Данный блок указывает что его обтекать нельзя, поэтому следующие данные будут отображаться ниже, а не где то сбоку. Своеобразный <br> только для блоков (div)  -->      <div id="send_line" class="corner">       <input type="text" class="msg" maxlength="500">      </div>     </div>       </body>   </html>     С клиентом разобрались, теперь приступаем к серверной стороне.   Серверная часть   В той же папке где и файл index.html создаем файл core.php   Code <?php   session_start();   /* Данные для подключения к БД */   define("DB_HOST", "localhost");   define("DB_USER", "root");   define("DB_PASS", "");   define("DB_NAME", "chat");   /* Фильтрация всех получаемых переменных */   $start = htmlspecialchars(stripslashes($_POST['start']));   $name = htmlspecialchars(stripslashes($_POST['name']));   $msg = htmlspecialchars(stripslashes($_POST['msg']));   $update = htmlspecialchars(stripslashes($_POST['update']));   $id = htmlspecialchars(stripslashes($_POST['id']));   /* Соединение с БД и если не удачное, то отправка ошибок клиенту */   $connect = mysql_connect(DB_HOST, DB_USER, DB_PASS);   if (!$connect) {    $data['err'] = 1;    echo json_encode($data);    exit;   }   $db_sel = mysql_select_db(DB_NAME,$connect);   if (!$db_sel) {    $data['err'] = 2;    echo json_encode($data);    exit;   }   # Установка языка записи в БД   mysql_query("SET NAMES utf8");   /* Если игрок загрузил страницу чата, то наш script.js передает серверу данные $_POST['start'] вот и обрабатываем эти данные */   if (!empty($start)) {    /* Если не существует сессия name, то возвращаем 0, в другом случае указываем логин игрока, который хранится в сессии, передаем id последнего сообщения */    if (empty($_SESSION['name'])) {     $data['ans'] = 0;    } else {     $data['ans'] = 1;     $data['login'] = $_SESSION['name'];     $msg_row = mysql_fetch_array(mysql_query("SELECT `post_id` FROM `post` ORDER BY `post_id` ASC"));     $data['id'] = $msg_row['post_id'];    }    echo json_encode($data); // Отправляем данные в формате json    exit;   }   /* Если переменная $name не пуста, то выполняем код */   if (!empty($name)) {    /* Ищем игрока в БД */    $sql = mysql_query("SELECT * FROM `users` WHERE `user_name`='".$name."'");    if (mysql_num_rows($sql) == 0) {     /* Если не находим, то создаем новую запись, запоминаем логин и передаем клиенту логин и id последнего сообщения */     mysql_query("INSERT INTO `users` (`user_name`,`user_online`,`last_update`) VALUES ('".$name."','1','".time()."')");     $data['ans'] = 0;     $_SESSION['name'] = $name;     $data['login'] = $_SESSION['name'];     $msg_row = mysql_fetch_array(mysql_query("SELECT `post_id` FROM `post` ORDER BY `post_id` ASC"));     $data['id'] = $msg_row['post_id'];    } else {     /* Если игрок в БД уже есть, то проверяем онлайн он или нет. Если онлайн, то выдаем ошибку, если нет, то делаем его онлайн и передаем нужные данные клиенту */     $row = mysql_fetch_array($sql);     if ($row['user_online'] == 0) {      mysql_query("UPDATE `users` SET `user_online`='1' WHERE `user_name`='".$name."'");      $data['ans'] = 0;      $data['login'] = $_SESSION['name'];      $msg_row = mysql_fetch_array(mysql_query("SELECT `post_id` FROM `post` ORDER BY `post_id` ASC"));      $data['id'] = $msg_row['post_id'];     } else {      $data['ans'] = 1;     }    }    echo json_encode($data);    exit;   }   /* Получение нового сообщения */   if (!empty($msg)) {    if (empty($msg)) { /* Если переменная пуста, то возвращаем 0 */     $data['ans'] = 0;    } else { /* В другом случае записываем в БД сообщение, обновляем запись игрока в БД (указываем что игрок онлайн и обновляем время последнего действия, нужно для отслеживания игроков онлайн) и отправляем нужные данные клиенту */     $t = time();     mysql_query("INSERT INTO `post` (`post_login`,`post_time`,`post_txt`) VALUES ('".$_SESSION['name']."','".$t."','".$msg."')");     mysql_query("UPDATE `users` SET `last_update`='".$t."', `user_online`='1' WHERE `user_name`='".$_SESSION['name']."'");     $data['ans'] = 1;     $data['login'] = $_SESSION['name'];     $data['time'] = date('H:i:s', $t);     $data['msg'] = $msg;    }    echo json_encode($data);    exit;   }   /* Если переменная $update не пуста (функция обновления на стороне клиента) */   if (!empty($update)) {    if (empty($update)) {     $data['ans'] = 0;    } else {     /* Выбираем всех игроков с базы */     $user = mysql_query("SELECT * FROM `users`");     $data['user'] = "";     while ($user_row = mysql_fetch_array($user)) {      /* Если игрок онлайн, то проверяем время его последнего действия и добавляем к нему 1 час (3600 сек) и запоминаем для передачи его имени клиенту. Если игрок в течении часа ничего не делал, то переводим его в режим оффлайн и убираем из списка игроков. Перевод игрока в режим оффлайн будет состоятся только в том случае если хоть 1 пользователь будет находится в чате. */      if ($user_row['user_online'] == 1) {       $t = $user_row['last_update']+3600;       if ($t >= time()) {        $data['user'] .= "<div>".$user_row['user_name']."</div>";       } else {        mysql_query("UPDATE `users` SET `user_online`='0' WHERE `user_name`='".$user_row['user_name']."'");       }      }     }     /* Выбираем все сообщения */     $msg_sql = mysql_query("SELECT * FROM `post` ORDER BY `post_id` ASC");     $data['msg'] = "";     while ($msg_row = mysql_fetch_array($msg_sql)) {      /* Производим проверку id. Если id игрока меньше чем id последнего сообщения, значит в БД появилось новое сообщение, выбираем его и запоминаем для передачи клиенту. Данное действие нужно для того что бы в чат клиенту добавлять по несколько сообщений, а не обновлять весь блок (div). Т.к. бывает нужно выделить какое то сообщение, а не можешь, т.к. блок обновляется и выделение сбрасывается. */      if ($id < $msg_row['post_id']) {       $data['msg'] .= "<div>[".date('H:i:s', $msg_row['post_time'])."] <strong>".$msg_row['post_login'].": </strong>".$msg_row['post_txt']."</div>";       $data['id'] = $msg_row['post_id'];      }     }    }    echo json_encode($data);    exit;   } 
   ?>     База данных   Code -- phpMyAdmin SQL Dump   -- version 3.2.3   -- http://www.phpmyadmin.net   --   -- Host: localhost   -- Generation Time: Sep 28, 2011 at 05:40 PM   -- Server version: 5.1.40   -- PHP Version: 5.3.3 
   SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; 
   --   -- Database: `chat`   -- 
   -- -------------------------------------------------------- 
   --   -- Table structure for table `post`   -- 
   CREATE TABLE IF NOT EXISTS `post` (     `post_id` int(11) unsigned NOT NULL AUTO_INCREMENT,     `post_login` varchar(50) NOT NULL,     `post_time` int(10) NOT NULL,     `post_txt` varchar(500) NOT NULL,     PRIMARY KEY (`post_id`)   ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 
   -- -------------------------------------------------------- 
   --   -- Table structure for table `users`   -- 
   CREATE TABLE IF NOT EXISTS `users` (     `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,     `user_name` varchar(50) NOT NULL,     `user_online` int(1) NOT NULL,     `last_update` int(10) NOT NULL,     PRIMARY KEY (`user_id`)   ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;        Фух, вроде везде комментарии оставил, если что не понятно пишите.   Для более подробного понимания кода:   - html, css читаем тут: htmlbook   - jquery читаем тут: api.jquery.com либо задаем вопросы в теме.
 
 |  
| 
 | 
 |    |  
| Кластер | Дата: Среда, 28 Сентября 2011, 18:52 | Сообщение # 2 |  
 
постоянный участник 
Сейчас нет на сайте 
 
 | Просто дополню русская документация по jQuery. 
   И для начинающих jQuery
 
 Сообщение отредактировал Кластер - Среда, 28 Сентября 2011, 18:55  |  
| 
 | 
 |    |  
| Sektoid | Дата: Четверг, 29 Сентября 2011, 04:48 | Сообщение # 3 |  
| 
 почетный гость 
Сейчас нет на сайте 
 
 | Спасибо   Хоть оно и не подойдет для моей игры, интересно было почитать.   Пеши есчо  
 |  
| 
 | 
 |    |  
| Assasin | Дата: Четверг, 29 Сентября 2011, 09:40 | Сообщение # 4 |  
 
web-coder 
Сейчас нет на сайте 
 
 | Тут описан процесс работы jquery (ajax) с php, можно изучить код и оптимизировать под свою игру.
 |  
| 
 | 
 |    |  
| Sektoid | Дата: Четверг, 29 Сентября 2011, 13:36 | Сообщение # 5 |  
| 
 почетный гость 
Сейчас нет на сайте 
 
 | Ну я это и имел ввиду - что в таком виде тупо вклеить его не получиться, но много полезной инфы из него вынести можно  
 |  
| 
 | 
 |    |  
| AGENTX001 | Дата: Четверг, 29 Сентября 2011, 14:23 | Сообщение # 6 |  
 
почётный гцупер 
Сейчас нет на сайте 
 
 | Assasin, у ты моя лапонька!!! Я с этим неделю маялся, и тут на тебе!) СПАСИБО!!
 |  
| 
 | 
 |    |  
| Or1ginal | Дата: Среда, 05 Октября 2011, 15:40 | Сообщение # 7 |  
 
постоянный участник 
Сейчас нет на сайте 
 
 | Это из-за меня чтоли, я тебе в чат извини.. :DD
 |  
| 
 | 
 |    |  
| Assasin | Дата: Среда, 05 Октября 2011, 18:58 | Сообщение # 8 |  
 
web-coder 
Сейчас нет на сайте 
 
 | Or1ginal,  
 |  
| 
 | 
 |    |  
| Or1ginal | Дата: Четверг, 06 Октября 2011, 10:35 | Сообщение # 9 |  
 
постоянный участник 
Сейчас нет на сайте 
 
 | А понятно, ну спасибо что простил  
 
 Сообщение отредактировал Or1ginal - Четверг, 06 Октября 2011, 10:36  |  
| 
 | 
 |    |  
| Kjut | Дата: Четверг, 06 Октября 2011, 10:35 | Сообщение # 10 |  
 
почетный гость 
Сейчас нет на сайте 
 
 | Асасинчик молодец  
  Портфолио   Команда Ninja World 
   Команде требуются художники
 |  
| 
 | 
 |    |  
| cougraAcc | Дата: Суббота, 15 Октября 2011, 01:58 | Сообщение # 11 |  
 
Яркая личность GD 
Сейчас нет на сайте 
 
 | Код отвратительный, верстка ужасная. Про js вообще молчу, такое ощущение что писал слепой калека. ТС ты бы книжки почитал...   p.s.  
 |  
| 
 | 
 |    |  
| Assasin | Дата: Суббота, 15 Октября 2011, 12:12 | Сообщение # 12 |  
 
web-coder 
Сейчас нет на сайте 
 
 | cougraAcc, ты мне тут по возмущайся! Ишь, моду взял  
 |  
| 
 | 
 |    |  
| Zeleboba | Дата: Воскресенье, 16 Октября 2011, 02:21 | Сообщение # 13 |  
| 
 постоянный участник 
Сейчас нет на сайте 
 
 | Ну я бы не сказал что код прям таки ужасен... Пойдет для первого года обучения, но вот защита... Это уже совсем весело XD юзаем PDO и не паримся о скулях
 |  
| 
 | 
 |    |  
| cougraAcc | Дата: Понедельник, 24 Октября 2011, 15:55 | Сообщение # 14 |  
 
Яркая личность GD 
Сейчас нет на сайте 
 
 | На кол автора посадить ^_^. Такой код только для стенда "Как не нужно писать программы". Добавлено (24.10.2011, 15:55) --------------------------------------------- Шучу автор няшка   , я любя придираюсь. 
 |  
| 
 | 
 |    |  
| romgerman | Дата: Понедельник, 24 Октября 2011, 17:35 | Сообщение # 15 |  
 
старожил 
Сейчас нет на сайте 
 
 | Ну jquery можно было бы не писать, просто вместо   Code <script type="text/javascript" src="/style/jquery-1.6.2.min.js"></script>     можно написать   Code <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>     И кстати я думаю не обязательно было пихать самую последнюю квери, даже 1.4 подошло бы.
 |  
| 
 | 
 |    |  
| cougraAcc | Дата: Вторник, 25 Октября 2011, 03:06 | Сообщение # 16 |  
 
Яркая личность GD 
Сейчас нет на сайте 
 
 | Quote (romgerman) И кстати я думаю не обязательно было пихать самую последнюю квери, даже 1.4 подошло бы.      Когда ты работаешь в оффлайне, то брать либу с гугла не очень удобно.
 |  
| 
 | 
 |    |  
| romgerman | Дата: Вторник, 25 Октября 2011, 20:42 | Сообщение # 17 |  
 
старожил 
Сейчас нет на сайте 
 
 | Ну мне всё равно, я просто выразил своё мнение и кастати такой урок есть здесь - http://ruseller.com/lessons.php?rub=32&id=758.
 |  
| 
 | 
 |    |  
| SouzNik | Дата: Среда, 25 Января 2012, 18:56 | Сообщение # 18 |  
| 
 был не раз 
Сейчас нет на сайте 
 
 | Спасибо! Очень долго искал нормальный чат и наконец нашел! 
   ---------------------------------------------   Заметил несколько дырок. Если пользователь раньше был зареган, то при входе в базе это все обновляется, а сам чел не может написать ничего. Страница заново просит логин. Для этого я сделал так:   В файле core.php надо заменить это:   Code    mysql_query("UPDATE users SET last_update = '".$t."', user_online = '1' WHERE user_name = '".$_SESSION['name']."'");     $data['ans'] = 0;        На это:   Code    mysql_query("UPDATE users SET last_update = '".$t."', user_online = '1' WHERE user_name = '".$_SESSION['name']."'");     $data['ans'] = 0;   $_SESSION['name'] = $name;      
   И так же я немного приукрасил)   Вот что у меня получилось:    
 
 Сообщение отредактировал SouzNik - Среда, 25 Января 2012, 18:57  |  
| 
 | 
 |    |     
		
		 
 |