Общение всегда привлекало пользователей. Ведь люди хотят общаться, делиться впечатлениями и задавать различные вопросы. Но создавая сайт не каждый начинающий разработчик может осуществить систему комментариев у себя на сайте, да и так, чтобы она имела привлекательным вид, кроме того пользователям присваивался персональный аватар. На нашем сайте уже не раз возникали просьбы, объяснить, показать или просто навести пример как данную функцию можно реализовать у себя на сайте.
В данном уроке мы расскажем и наглядно покажем как сделать отличную систему комментариев для сайта с помощью PHP ,MySQL и AJAX. Также будет использована интеграция с gravatar.com. Для начала рассмотрим построение структуры Данный код генерируется PHP с классом Comment.
demo.php
<div class="comment"> <div class="avatar"> <a href="http://www.rudebox.org.ua"> <img src="http://www.gravatar.com/avatar/112fdf7a8fe3609e7af2cd3873b5c6bd?size=50&default=http%3A%2F%2Fdemo.tutorialzine.com%2F2010%2F06%2Fsimple-ajax-commenting-system%2Fimg%2Fdefault_avatar.gif"> </a> </div> <div class="name"><a href="http://www.rudebox.org.ua">Имя пользователя</a></div> <div title="Added at 06:40 on 30 Jun 2010" class="date">30 Jun 2010</div> <p>Текст комментария</p> </div>
div avatar содержит ссылку (если пользователь ввел правильный URL при размещении комментария) и изображение аватара, которое мы получаем с gravatar.com. Другим важным элементом в XHTML является форма комментария. Она отправляется с помощью POST. Все поля, кроме URL, должны быть заполнены.
demo.php
<div id="addCommentContainer"> <p>Добавить комментарий</p> <form id="addCommentForm" method="post" action=""> <div> <label for="name">Имя</label> <input type="text" name="name" id="name" /> <label for="email">Email</label> <input type="text" name="email" id="email" /> <label for="url">Вебсайт (не обязательно)</label> <input type="text" name="url" id="url" /> <label for="body">Содержание комментария</label> <textarea name="body" id="body" cols="20" rows="5"></textarea> <input type="submit" id="submit" value="Отправить" /> </div> </form> </div>
Форма отправляется с помощью AJAX. Проверка выполняется в фоновом режиме в submit.php. Каждое поле имеет соответствующий элемент label, с установленным атрибутом for.
PHP обрабатывает коммуникацию с базой данных MySQL и генерирует разметку для комментария. Он также получает окончание запроса AJAX и вставляет данные комментария в таблицу comments.
demo.php
/* / Выбираем все комментарии и наполняем массив $comments объектами */ $comments = array(); $result = mysql_query("SELECT * FROM comments ORDER BY id ASC"); while($row = mysql_fetch_assoc($result)) { $comments[] = new Comment($row); }
Запрос MySQL выбирает все записи из таблицы и заполняет массив $comments объектами класса comment. Данный массив выводится далее при выполнении скрипта.
demo.php
/* / Вывод комментариев один за другим: */ foreach($comments as $c){ echo $c->markup(); }
Каждый комментарий имеет метод markup(), который генерирует правильный HTML код, готовый для вывода на страницу. Ниже приведены определения класса и метода. Класс получает строку из базы данных (получаемую с помощью mysql_fetch_assoc() ) и сохраняет ее в переменной $data. Она доступна только методу класса.
comment.class.php
class Comment { private $data = array(); public function __construct($row) { /* / Конструктор */ $this->data = $row; } public function markup() { /* / Данный метод выводит разметку XHTML для комментария */ // Устанавливаем псевдоним, чтобы не писать каждый раз $this->data: $d = &$this->data; $link_open = ''; $link_close = ''; if($d['url']){ // Если был введн URL при добавлении комментария, // определяем открывающий и закрывающий теги ссылки $link_open = '<a href="'.$d['url'].'">'; $link_close = '</a>'; } // Преобразуем время в формат UNIX: $d['dt'] = strtotime($d['dt']); // Нужно для установки изображения по умолчанию: $url = 'http://'.dirname($_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"]).'/img/default_avatar.gif'; return ' <div> <div> '.$link_open.' <img src="http://www.gravatar.com/avatar/'.md5($d['email']).'?size=50&default='.urlencode($url).'" /> '.$link_close.' </div> <div>'.$link_open.$d['name'].$link_close.'</div> <div title="Added at '.date('H:i \o\n d M Y',$d['dt']).'">'.date('d M Y',$d['dt']).'</div> <p>'.$d['body'].'</p> </div> '; }
Скрипт определяет адрес URL, на котором выполняется, и определяет точный адрес изображения default_avatar.gif. Данное изображение передается на параллельно с хэшем md5, и если никакого аватар не было найдено для переданного email адреса, то будет выведено альтернативное изображение.
comment.class.php
public static function validate(&$arr) { /* / Данный метод используется для проверки данных отправляемых через AJAX. / / Он возвращает true/false в зависимости от правильности данных, и наполняет / массив $arr, который преается как параметр либо данными либо сообщением об ошибке. */ $errors = array(); $data = array(); // Используем функцию filter_input, введенную в PHP 5.2.0 if(!($data['email'] = filter_input(INPUT_POST,'email',FILTER_VALIDATE_EMAIL))) { $errors['email'] = 'Пожалуйста, введите правильный Email.'; } if(!($data['url'] = filter_input(INPUT_POST,'url',FILTER_VALIDATE_URL))) { // Если в поле URL был введн неправильный URL, // действуем так, как будто URL не был введен: $url = ''; } // Используем фильтр с возвратной функцией: if(!($data['body'] = filter_input(INPUT_POST,'body',FILTER_CALLBACK,array('options'=>'Comment::validate_text')))) { $errors['body'] = 'Пожалуйста, введите текст комментария.'; } if(!($data['name'] = filter_input(INPUT_POST,'name',FILTER_CALLBACK,array('options'=>'Comment::validate_text')))) { $errors['name'] = 'Пожалуйста, введите имя.'; } if(!empty($errors)){ // Если есть ошибки, копируем массив $errors в $arr: $arr = $errors; return false; } // Если данные введены правильно, подчищаем данные и копируем их в $arr: foreach($data as $k=>$v){ $arr[$k] = mysql_real_escape_string($v); } // email дожен быть в нижнем регистре: $arr['email'] = strtolower(trim($arr['email'])); return true; }
Метод validate() (также часть класса) определен как static. Это означает, что его можно вызвать непосредственно с помощью конструкции Comment::validate(), без создания объекта класса. Данный метод проверяет данные, которые передаются через AJAX. Метод использует новую функцию фильтра, которая стала доступна в PHP 5.2.0.. Например, filter_input(INPUT_POST,’url’,FILTER_VALIDATE_URL) означает, что мы проверяем, является ли $_POST['url'] правильным адресом URL. Если это так, то функция возвращает значение переменной, в другом случае она возвращает значение false.
comment.class.php
private static function validate_text($str) { /* / Данный метод используется как FILTER_CALLBACK */ if(mb_strlen($str,'utf8')<1) return false; // Кодируем все специальные символы html (<, >, ", & .. etc) и преобразуем // символ новой строки в тег <br>: $str = nl2br(htmlspecialchars($str)); // Удаляем все оставщиеся символы новой строки $str = str_replace(array(chr(10),chr(13)),'',$str); return $str; }
Последний метод validate_text передаётся в качестве возвратной функции в два вызова filter_input. Он преобразует все специальные символы HTML, что эффективно блокирует атаки XSS. Также он заменяет символы новой строки тегами <br />.
submit.php
/* / Данный массив будет наполняться либо данными, / которые передаются в скрипт, / либо сообщениями об ошибке. /*/ $arr = array(); $validates = Comment::validate($arr); if($validates) { /* Все в порядке, вставляем данные в базу: */ mysql_query(" INSERT INTO comments(name,url,email,body) VALUES ( '".$arr['name']."', '".$arr['url']."', '".$arr['email']."', '".$arr['body']."' )"); $arr['dt'] = date('r',time()); $arr['id'] = mysql_insert_id(); /* / Данные в $arr подготовлены для запроса mysql, / но нам нужно делать вывод на экран, поэтому / готовим все элементы в массиве: /*/ $arr = array_map('stripslashes',$arr); $insertedComment = new Comment($arr); /* Вывод разметки только-что вставленного комментария: */ echo json_encode(array('status'=>1,'html'=>$insertedComment->markup())); } else { /* Вывод сообщений об ошибке */ echo '{"status":0,"errors":'.json_encode($arr).'}'; }
submit.php получает комментарий из данных через запрос AJAX. Проверяет его и выводит объект JSON, в котором содержится либо разметка XHTML с вставленным комментарием, либо список ошибок. jQuery использует свойство status для определения того, что нужно выводить - либо сообщение об ошибках, либо добавлять разметку комментария к странице.
Успешный ответ:
{ "status": 1, "html": "Html Code Of The Comment Comes Here..." }
Свойство html содержит код комментария.
Ответ об ошибке:
{ "status": 0, "errors": { "email": "Please enter a valid Email.", "body": "Please enter a comment body.", "name": "Please enter a name." } }
При наличии ошибки jQuery проходит циклом по объекту ошибок и выводит сообщения рядом с полями, в которых есть ошибки.
Теперь, когда разметка правильно генерируется и отображается на странице, мы можем перейти к заданию стилей.
styles.css
.comment, #addCommentContainer{ /* Стиль для комментариев */ padding:12px; width:400px; position:relative; background-color:#fcfcfc; border:1px solid white; color:#888; margin-bottom:25px; /* Скругленные углы и тени CSS3 */ -moz-border-radius:10px; -webkit-border-radius:10px; border-radius:10px; -moz-box-shadow:2px 2px 0 #c2c2c2; -webkit-box-shadow:2px 2px 0 #c2c2c2; box-shadow:2px 2px 0 #c2c2c2; } .comment .avatar{ /* / Аватар позиционируется абсолютно. / Внешнее смещение для div комментария /*/ height:50px; left:-70px; position:absolute; width:50px; background:url('img/default_avatar.gif') no-repeat #fcfcfc; /* Центрируем вертикально: */ margin-top:-25px; top:50%; -moz-box-shadow:1px 1px 0 #c2c2c2; -webkit-box-shadow:1px 1px 0 #c2c2c2; box-shadow:1px 1px 0 #c2c2c2; }
div .comment и #addCommentContainer имеют одинаковый стиль. Используется несколько правил CSS3 для скругления углов и отражения теней.
styles.css
.comment .avatar img{ display:block; } .comment .name{ font-size:20px; padding-bottom:10px; color:#ccc; } .comment .date{ font-size:10px; padding:6px 0; position:absolute; right:15px; top:10px; color:#bbb; } .comment p, #addCommentContainer p{ font-size:18px; line-height:1.5; overflow-x:hidden; } #addCommentContainer input[type=text], #addCommentContainer textarea{ /* Стиль для ввода */ display:block; border:1px solid #ccc; margin:5px 0 5px; padding:3px; font-size:12px; color:#555; font-family:Arial, Helvetica, sans-serif; } #addCommentContainer textarea{ width:300px; } label{ font-size:10px; } label span.error{ color:red; position:relative; right:-10px; } #submit{ /* Кнопка "Отправить" */ background-color:#58B9EB; border:1px solid #40A2D4; color:#FFFFFF; cursor:pointer; font-family:'Myriad Pro',Arial,Helvetica,sans-serif; font-size:14px; font-weight:bold; padding:4px; margin-top:5px; -moz-border-radius:4px; -webkit-border-radius:4px; border-radius:4px; } #submit:hover{ background-color:#80cdf5; border-color:#52b1e2; }
Во второй части мы задаем стили для комментариев и элементов формы. Отметим селектор input[type=text], который выделяет элементы в зависимости от атрибута type. Теперь рассмотрим jQuery.
script.js
$(document).ready(function(){ /* Следующий код выполняется только после загрузки DOM */ /* Данный флаг предотвращает отправку нескольких комментариев: */ var working = false; /* Ловим событие отправки формы: */ $('#addCommentForm').submit(function(e){ e.preventDefault(); if(working) return false; working = true; $('#submit').val('Working..'); $('span.error').remove(); /* Отправляем поля формы в submit.php: */ $.post('submit.php',$(this).serialize(),function(msg){ working = false; $('#submit').val('Submit'); if(msg.status){ /* / Если вставка была успешной, добавляем комментарий / ниже последнего на странице с эффектом slideDown /*/ $(msg.html).hide().insertBefore('#addCommentContainer').slideDown(); $('#body').val(''); } else { /* / Если есть ошибки, проходим циклом по объекту / msg.errors и выводим их на страницу /*/ $.each(msg.errors,function(k,v){ $('label[for='+k+']').append('<span>'+v+'</span>'); }); } },'json'); }); });
Мы используем вызов функции $(document).ready(), которая привязывает функцию к событию загрузка контента DOM. Переменная working действует как флаг, который сигнализирует о том, что запрос AJAX находится в работе (таким образом предотвращается дублирование одного и того же комментария).
Примечание!
Чтобы запустить скрипт на вашем сервере нужно создать таблицу comments в вашей базе данных MySQL. Вы можете сделать это с помощью кода SQL из файла table.sql, который надо ввести на закладке SQL в phpMyAdmin. Затем нужно установить параметры соединения с базой данных MySQL в файле connect.php.
Материал взят из зарубежного источника. И представлен исключительно в ознакомительных целях.