Гостевая книга на php и MySQL

Очень распространенная задача для веб-мастера – как написать гостевую книгу на PHP и MySQL. Конечно же можно скачать готовый скрипт и вклеить его в свой дизайн сайта, что настоятельно не рекомендую делать.

Причин для этого несколько: используя готовые скрипты мы ничему не научимся, руками мы сделаем защищённую, аккуратную и «быструю» гостевую книгу, что не всигда скажешь о скаченных.

Ничего сложного в этом нет (вполне нормальный урок для начинающего программиста на php и MySQL), да и возможности самой гостевой не самые большие:

  1. проверка вводимых пользователем данных,
  2. запись их в базу данных,
  3. постраничный вывод,
  4. возможность удалять записи.

Для тех, кто хочет больше возможностей, советую создать редактирование записей и комментирование их (так же несложно).

Допустим, что у вас уже настроен PHP, MySQL и веб-сервер. Если нет и Вы не хотите возиться с муторной настройкой, то скачайте Denver – автоматически настроенный сервер, всё что нам понадобиться там ест: Apach + php + MySQL.

Конечно же начнём с создания таблицы для хранения данных гостевой книги. Всё, что нам необходимо знать от пользователя, это его имя (или ник) и сам комментарий. При желании пользователь сможет сообщить адреса электронной почты и домашней странички. Так же нам понадобится ещё одно поле: уникальный идентификатор для каждой записи. Ну и дата, конечно.

Вот что должно получиться:

CREATE TABLE gb (
 id int(10) unsigned NOT NULL auto_increment,
 datetime datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
 name varchar(100) NOT NULL,
 email varchar(100),
 www varchar(100),
 message text NOT NULL,
 PRIMARY KEY (id)
 );

Теперь можно приступать к написанию самого скрипта. Для начала создадим файл с настройками гостевой книги. Советую делать подобный файл при написании всех скриптов (и инклудить его где необходимо функциями include(‘falename’) или once_include(‘filename’)).

С помощью такого файлы можно быстро редактировать настройки, не разбираясь в написанном коде:

<?php
 // константы
 define('PATH', '/gb/'); // путь к скрипту гостевой книги
 define('RECSPERPAGE', 10); // количество записей на одной странице
 define('ADMIN_EMAIL', ' example@sexample.ruЭтот e-mail защищен от спам-ботов. Для его просмотра в вашем браузере должна быть включена поддержка Java-script '); // email изменить на свой
 define('ERROR_LOG_FILE', 'logs/error.log'); // файл лога ошибок

 // Параметры Базы Данны
 define('DBHOST', 'localhost'); // имя хоста
 define('DBUSER', 'root'); // имя пользователя
 define('DBPASSWD', ''); // пароль пользователя к БД
 define('DBNAME', 'test'); // имя базы данных
 ?>

Подумаем, какие функции в гостевой книге нам понадобятся. Нам необходимо будет взаимодействовать с СУБД (напомню, мы выбрали MySQL), обрабатывать вводимые пользователем данные (никогда «не доверяйте» вводимым в формы данным). Так же для функций администрирования нам понадобится отличать администратора от простых пользователей (на будущее лучше выводить админ-пенель для редактирования в отдельный фал и вообще в отдельную директорию, закрывая её пароль).

Начнём с работы с СУБД

<?php
 /** recource db_connect ( string host, string user, string passwd, string dbname )
 * Подключение к СУБД и открытие базы данных
 */
 function db_connect($host, $user, $passwd, $dbname) {
 $link = mysql_pconnect($host, $user, $passwd) or die('Could not connect to database');
 mysql_select_db($dbname) or die('Could not select database');

 return $link;
 }

 /** Выполняет запрос к БД
 *
 * @param текст запроса
 * @return resource id
 */

 function db_query($query) {
 $result = mysql_query($query)
 or die('Bad database query');

 return $result;
 }

 /** Выполняет запрос к БД (placeholder)
 *
 * @param текст запроса
 * @param*
 * @return resource id
 */

 function db_query_ex($query) {
 $values = func_get_args();
 array_shift($values);
 $i = 0;

 return db_query(preg_replace('%?%e', '"'".addslashes($values[$i++])."'"',
 $query));
 }
 ?>

Проверка и фильтрация вводимых пользователем данных).

<?php
 /**
 * Проверяет является ли строка адресом e-mail
 */

 function strings_isemail($string) {
 return preg_match('%[-.w]+@[-w]+(?:.[-w]+)+%', $string);
 }

 /**
 * Добавление ссылок на http и e-mail
 */

 function strings_addlinks($string) {
 return preg_replace('%((?:http|ftp)://[-w]+(?:.[-w]+)+b[-w:@&?=+,!/~*$.'%]*)(?<![.,?!)])%i','<a href="1">1<a>',$string);
 }

 /**
 * Чистка строки
 */

 function strings_clear($string) {
 $string = trim($string);
 $string = stripslashes($string);

 return htmlspecialchars($string, ENT_QUOTES);
 }

 /**
 * Обрезание строки
 */

 function strings_stripstring($text, $wrap, $length) {
 $text = preg_replace('%(S{'.$wrap.'})%', '1 , $text);

 return substr($text, 0, $length);
 }
 ?>

Написание аутентификации для администратора (отличить обычного пользователя от пользователя с возможностями удаления и редактирования) я оставляю вам как «домашнее задание». Есть достаточно много способов и их обсуждение - тема отдельной статьи. Я

Далее идёт достаточно большой модуль, в котором содержится почти весь HTML-код гостевой книги, - шаблон. В нём нет ничего сложного и его написание можно вполне под силу верстальщику сайта, если у вас таковой имеется.

<?php
 /**
 * заголовок страницы
 */
 function template_header($page) {
 ?><html>
 <head>
 <title>page <?=$page?> < fjGuestbook Demo</title>
 <style>
 body {
 padding: 15px;
 margin: 0;
 color: #333;
 background-color: #eee;
 border-left: 30px solid #adba8e;
 font: 500 .9em verdana, arial, helvetica;
 }
 a:link{
 color: #250;
 }
 a:visited{
 color: #639;
 }
 a:active,a:hover {
 color: #c00;
 text-decoration: underline;
 }
 h1 {
 font-size: 150%;
 }
 h2 {
 font-size: 110%;
 }
 .c {
 margin-bottom: 10px;
 }
 .cn {
 background-color: #d2d6bc;
 padding: 2px 4px;
 margin-bottom: 4px;
 }
 </style>
 </head>
 <body>
 <h1>Гостевая книга</h1><?php
 }

 /**
 * подвал страницы
 */
 function template_footer() {
 ?>
 <p>Гостевая книга Copyright © 2008
 <a href="http://www.woolfs.ru">CyberWoolfs – уроки создания сайтов</a></p>
 </body></html>
 <?php
 }

 /**
 * форма добавления новой записи
 */

 function template_form($name, $email, $www, $message, $error) {
 // вывод сообщения об ошибке

 function error($error) {
 if($error) echo '<br><font color=#880000>'.$error.
 '</font>';
 }

 echo '<h2>Добавить новое сообщение</h2>
 <p><table cellspacing="2" cellpadding="2" border="0">
 <form action='.PATH.'?add=1 method=post><tr>
 <td>Имя<font color=#880000>*</font>:</td>
 <td><input type=text name="name" size=30
 maxlength=100 value="'.$name.'">';
 @error($error['name']);

 echo '</td>
 </tr><tr>
 <td>Email:</td>
 <td><input type=text name="email" size=30
 maxlength=100 value="'.$email.'">';
 @error($error['email']);

 echo '</td>
 </tr><tr>
 <td>URL:</td>
 <td><input type=text name="www" size=30
 maxlength=100 value="'.$www.'">';

 echo '</td>
 </tr><tr>
 <td>Сообщение<font color=#880000>*</font>:</td>
 <td><textarea cols=40 rows=5
 name="message">'.$message.'</textarea>';
 @error($error['message']);

 echo '</td>
 </tr><tr>
 <td> </td>
 <td><small><font color=#880000>*</font>
 — Обязательные поля</small></td>
 </tr><tr>
 <td> </td>
 <td><input name="sb" type=submit
 value="Добавить сообщение"></td>
 </form></tr>
 </table>';
 }

 /**
 * печать одной записи гостевой книги
 */

 function template_show_body($id, $name, $email, $www, $message, $datetime) {
 $out = '<div class=c><div class=cn><b>'.$name.'</b>';

 // если есть email или homepage - печатаем и
 if($email || $www) {
 $out .= '( ';
 if($email) $out .= ' <a href=mailto:'.$email.'>email</a>';
 if($email && $www) $out .= ' | ';
 if($www) $out .= ' <a href='.$www.'>www</a>';
 $out .= ' )';
 }

 $out .= ' пишет '.$datetime.':</div>'.$message.'</div>';

 // если гостевую книгу просматривает администратор - выводим кнопку
 // удаления ненужной нам записи
 if(auth_is_admin()) {
 $out .= '<div class=c>[ <a href='.PATH.'?admin=1&del='.$id.
 '>удалить</a> ]</div>';
 }

 return $out;
 }

 ?>

И вот, мы наконец-то дошли до главного. До модуля гостевой книги. Постараюсь написать побольше комментариев, чтобы вам было понятно.

<?php
 /**
 * Создание таблицы, если её ещё нет
 */

 function gb_install() {
 db_query(
 'CREATE TABLE IF NOT EXISTS gb (
 id int(10) unsigned NOT NULL auto_increment,
 datetime datetime NOT NULL default '0000-00-00 00:00:00',
 name varchar(100) NOT NULL default '',
 email varchar(100) default NULL,
 www varchar(100) default NULL,
 message text NOT NULL,
 PRIMARY KEY (id),
 INDEX (datetime)
 ) TYPE=MyISAM;'
 );
 }

 /**
 * Добавление записи в гостевую книгу
 */

 function gb_add($name, $email, $www, $message, &$error) {
 // проверяем правильность заполнения полей
 $error = '';
 if(empty($name))
 $error['name'] = 'Это обязательное поле';
 if(empty($message))
 $error['message'] = 'Это обязательное поле';
 if(!empty($email) && !strings_isemail($email))
 $error['email'] = 'Это не email';

 // если не было ошибок - добавляем
 if(!$error) {
 // чистим данные
 $name = strings_clear($name);
 $message = strings_clear($message);
 $name = strings_stripstring($name, 15, 100);
 $email = strings_stripstring($email, 100, 100);
 $www = strings_stripstring($www, 100, 100);
 $message = strings_stripstring($message, 100, 2000);
 $message = nl2br($message);

 // если пользователь поленился написать http:// перед адресом - сделаем
 // это за него
 if(!empty($www) && 'http://' != substr($www, 0, 7))
 $www = 'http://'.$www;

 // запрос на добавление записи в базу данных
 db_query_ex('INSERT INTO gb (name, email, www, message, datetime)
 VALUES(?, ?, ?, ?, NOW())', $name, $email, $www, $message);

 // перекидываем браузер на первую страницу
 header('Location: '.PATH."?page=1");
 }
 }

 // удаление записи из гостевой книги
 function gb_delete($id) {
 // запрос на удаление записи из базы данных
 // WHERE id = '.$id указывает на запись, которую следует удалить
 db_query_ex('DELETE FROM gb WHERE id = ?', $id);

 // И снова перекидываем пользователя
 header('Location: '.PATH."?page=1"); // ???
 }

 // вывод страницы с записями
 function gb_show($page) {
 // положение первой записи страницы
 $begin = ($page - 1) * 10;

 // выборка записей из базы данных
 // SELECT * FROM gb - все поля из бд gb
 // ORDER BY datetime DESC - сортировка по дате, новые сверху
 // LIMIT '.$begin.','.RECSPERPAGE - ограничение:
 // RECSPERPAGE (см. defines.php) записей начиная с $begin
 $result = db_query('SELECT * FROM gb ORDER BY datetime DESC LIMIT '.
 $begin.', '.RECSPERPAGE);
 $out = '';

 // цикл по всем выбранным записям
 while($row = mysql_fetch_array($result))
 $out .= template_show_body($row['id'], $row['name'], $row['email'],
 $row['www'], $row['message'], $row['datetime']);

 // уничтожаем результат
 mysql_free_result($result);

 echo $out;
 }

 // вывод списка страниц
 function gb_showpages($current) {
 // узнаем число записей в гостевой книге
 $result = db_query('SELECT * FROM gb');
 $rows = mysql_num_rows($result);
 if($rows) {
 $pages = ceil($rows / RECSPERPAGE);

 // печатаем ссылки на страницы (номер текущей страницы не является ссылкой)
 echo '<div class=c>';
 for($i = 1; $i <= $pages; $i++) {
 if($i != $current)
 echo ' | <a href='.PATH.'?page='.$i.'>'.$i.'</a>';
 else
 echo ' | '.$i;
 }
 echo ' |';

 // если это не полследняя страница печатаем ссылку "Дальше"
 if($current < $pages)
 echo ' >a href='.PATH.'?page='.($current + 1).
 '>Дальше >></a>';
 echo '</div>';
 }
 }

 ?>

И наконец, последний штрих – объединяем это вместе:

<?php
 // подключаем модули
 require_once 'my/defines.php';
 require_once 'my/template.php';

 require_once 'engine/lib/strings.php';
 require_once 'engine/lib/auth.php';
 require_once 'engine/lib/bd.php';
 require_once 'engine/gb.php';

 // подключаемся к БД
 db_connect(DBHOST, DBUSER, DBPASSWD, DBNAME);

 // создаём таблицу, если её нет
 gb_install();

 // получаем данные формы, если форма была отправлена
 if (!empty($_POST['sb'])) {
 $name = @$_POST['name'];
 $email = @$_POST['email'];
 $www = @$_POST['www'];
 $message = @$_POST['message'];
 $formerr = '';
 }
 else {
 $name = $email = $www = $message = $formerr = '';
 }

 // если в GET-запросе не указан номер страницы, выводим первую
 if(is_numeric(@$_GET['page']))
 $page = $_GET['page'];
 else
 $page = 1;

 // если нужно добавить запись, добавляем
 if(@$_GET['add'])
 gb_add($name, $email, $www, $message, $formerr);

 // если нужно удалить запись, удаляем
 if(isset($_GET['del']) && auth_is_admin())
 gb_delete(intval($_GET['del']));

 // печатаем гостевую книгу
 template_header($page);
 gb_showpages($page);
 gb_show($page);
 gb_showpages($page);
 template_form($name, $email, $www, $message, $formerr);
 template_footer();
 ?>

Как видите, несмотря на слегка объёмный код, ничего сложного в гостевой книге на php и mysql не было. Данный скрипт не является абсолютно верным решением, лучше будет, если Вы его перед применением подредактируете и проверите на уязвимости.