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


Прислал: Artem Sapegin [ 06.05.2002 @ 23:58 ]
Раздел:: [ Статьи по PHP ]


3 мая 2002 г.

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

Допустим, что у вас уже есть 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)
);

Таблица у нас есть. Теперь можно приступать к программированию.

Для начала определим константы, которые понадобятся нам в дальнейшем:

<?
/*
 * defines.php -- константы
 */

// общие константы
define('PATH', '/gb/'); // путь к гостевой книге
define('RECSPERPAGE', 10); // количество записей на одной странице

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

Напишем модуль для работы с СУБД MySQL. Я вынес все функции работающие с MySQL в отдельный модуль, чтобы их можно было легко переписать при смене СУБД. Думаю, комментариев в исходнике будет достаточно.

<?
/*
 * bd.php -- работа с MySQL
 */

// подключение к СУБД и открытие базы данных
function db_connect($host, $user, $passwd, $dbname)
{
  $link = @mysql_connect($host, $user, $passwd) or die('Не могу подключиться к серверу баз данных');
  @mysql_select_db($dbname) or die('Не могу открыть базу данных &laquo;'.$dbname.'&raquo;');
  return $link;
}

// запрос к БД
function db_query($query)
{
  $result = @mysql_query($query) or die('Не могу сделать запрос к базе данных');
  return $result;
}

// получение текущей записи результата в виде массива
function db_fetch_array($result)
{
  return mysql_fetch_array($result);
}

// уничтожение результата
function db_free_result($result)
{
  return mysql_free_result($result);
}

// получение числа записей (строк) в результате
function db_num_rows($result)
{
  return mysql_num_rows($result);
}
?>

Для написания нормальной гостевой книги нам понадобятся еще две библиотеки. Первая — работа со строками:

<?
/*
 * strings.php -- функции для работы со строками
 */

  //проверяет является ли строка адресом e-mail
  function strings_isemail($string)
  {
    return ereg(
          '^([a-zA-Z0-9_]|-|.)+'.
          '@'.
          '([a-zA-Z0-9_]|-|.)+'.
          '[a-zA-Z]{2,4}$',
          $string);
  }
  
  //добавление ссылок на http и e-mail
  function strings_addlinks($string)
  {
    $string = ereg_replace("(http://[a-zA-Z0-9_.#%?/&=-]*)", "<a href="1">1</a>", $string);
    $string = ereg_replace("(([a-zA-Z0-9_]|-|.)+@([a-zA-Z0-9_]|-|.)+[a-zA-Z]{2,4})", "<a href="mailto:1">1</a>", $string);

    return $string;
  }

  // чистка строки
  function strings_clear($string)
  {
    $string = stripslashes($string); //восстановление кавычек после формы
    $string = htmlspecialchars($string); //замена специальных символов их кодами
    $string = str_replace("'", "&#39;", $string); //замена апострофа его кодом (нужно для того, чтобы нормально работали запросы)
    $string = trim($string); //снос ведущих пробелов
    
    return $string;
  }
  
  // кастрирование строки
  function strings_stripstring($text, $wrap, $length)
  {
    // разбиваем очень длинные слова (длиннее $wrap) на несколько маленьких
    $wordlen = 0;
    for($i = 0; $i < strlen($text); $i++)
    {
      $text2 .= $text[$i];
      if($text[$i] != " ")
        $wordlen++;
      else
        $wordlen = 0;
      if($wordlen > $wrap)
      {
        $text2 .= " ";
        $wordlen = 0;
      }
    }
    $text = $text2;
    // обрезаем строку до нужной длинны ($length)
    $text = substr($text, 0, $length);
    
    return $text;
  }

  // замена символов перевода строки и возвата каретки на <br>
  function strings_addbreaks($string)
  {
    return str_replace("rn", "<br>", $string);
  }
?>

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

<?
/*
 * auth.php -- аутентификация пользователей
 */

/*
 * ВНИМАНИЕ! Ни в коем случае не используйте этот файл в реальных проектах.
 * Сделайте проверку пароля или что-то в этом духе, иначе вашу гостевую просто
 * сломают.
 */

// проверка: администратор или обычный пользователь
function auth_is_admin()
{
  global $HTTP_GET_VARS;
  return $HTTP_GET_VARS['admin'];
}

?>

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

<?
/*
 * template.php -- шаблон
 */

// заголовок страницы
function template_header($page)
{
  print '<html>
<head>
<title>page '.$page.' &lt; madman/gb</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;
}
.c{margin-bottom: 10px;}
.cn{
background-color: #d2d6bc;
padding: 2px 4px;
margin-bottom: 4px;
}
h2{font: 700 20pt/24pt verdana, arial, helvetica;}
</style>
</head>
<body>
<h2>Гостевая книга Васи Пупкина</h2>';
}

// окончание страницы
function template_footer()
{
  print '<p>Guestbook by Artem Sapegin v 1.0; [c] zooz</p></body></html>';
}

// форма добавления новой записи
function template_form($name, $email, $www, $message, $error)
{
  // вывод сообщения об ошибке
  function error($error)
  {
    if($error) print '<br><font color=#880000>'.$error.'</font>';
  }
  
  print '<h2>Добавить новое сообщение</h2>
<p><table cellspacing="2" cellpadding="2" border="0"><form action='.PATH.'?add=1 method=post><tr>
<td>Имя:</td>
<td><input type=text name="name" size=30 maxlength=100 value="'.$name.'">';
  error($error['name']);
  print '</td>
</tr><tr>
<td>Email:</td>
<td><input type=text name="email" size=30 maxlength=100 value="'.$email.'">';
  error($error['email']);
  print '</td>
</tr><tr>
<td>URL:</td>
<td><input type=text name="www" size=30 maxlength=100 value="'.$www.'">';
  print '</td>
</tr><tr>
<td>Сообщение:</td>
<td><textarea cols=40 rows=5 name="message">'.$message.'</textarea>';
  error($error['message']);
  print '</td>
</tr><tr>
<td>&nbsp;</td>
<td><input 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.'?del='.$id.'>удалить</a> ]</div>';
  }
  
  return $out;
}

?>

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

<?
/*
 * gb.php -- гостевая книга
 */

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

  // если не было ошибок -- добавляем
  if(!$error)
  {
    // чистим данные. эти функции находятся в модуле strings.php
    $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, 40, 2000);
    $message = strings_addlinks($message);
    $message = strings_addbreaks($message);
    // если пользователь поленился написать http:// перед адресом -- сделаем это за него
    if($www)
      if(!ereg("^http://(.*)$", $www)) $www = 'http://'.$www;

    // запрос на добавление записи в базу данных
    db_query("INSERT INTO gb (name, email, www, message, datetime) VALUES('".$name."', '".$email."', '".$www."', '".$message."', NOW())");
    // перекидываем браузер на первую страницу
    // это нужно, чтобы, если пользователь нажмет кнопку Refresh, запись не добавилась еще раз
    header('Location: '.PATH."?page=1nn"); // ???
  }
}

// удаление записи из гостевой книги
function gb_delete($id)
{
  // запрос на удаление записи из базы данных
  // WHERE id = '.$id указывает на запись, которую следует удалить
  db_query('DELETE FROM gb WHERE id = '.$id);
  header('Location: '.PATH."?page=1nn"); // ???
}

// вывод страницы с записями
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);

  // цикл по всем выбранным записям
  while($row = db_fetch_array($result))
  {
    $out .= template_show_body($row['id'], $row['name'], $row['email'], $row['www'], $row['message'], $row['datetime']);
  }
  // уничтожаем результат
  db_free_result($result);
  print $out;
}

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

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

?>

Остался последний штрих — объединить все это вместе. Тут уж совсем все просто:

<?
/*
 * Guestbook by Artem Sapegin v 1.0; ©2002
 * vampire@au.ru | http://madman.km.ru/
 */
 
/*
 * index.php -- главный файл
 */
 
// подключаем модули
require('my/defines.php');
require('my/template.php');

require('engine/lib/strings.php');
require('engine/lib/auth.php');
require('engine/lib/bd.php');
require('engine/gb.php');

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

$name = $HTTP_POST_VARS['name'];
$email = $HTTP_POST_VARS['email'];
$www = $HTTP_POST_VARS['www'];
$message = $HTTP_POST_VARS['message'];

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

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

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

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

?>

Как видите, ничего сложного не было. Но если вопросы все же возникнут, постараюсь помочь.

Copyright [c] 2000–2002 Artem Sapegin aka Virtual Vampire