Открыть в новом окне

Как написать гостевую книгу

Итак, настало время попробовать написать простую гостевую книгу.
Первое, что нам для этого понадобиться - это форма которую и будут заполнять посетители при добавлении записей в книгу. Данная форма позволит посетителю ввести свое имя, e-mail, город, страну, адрес Web сайта и краткое описание его описание. Наш скрипт не будет обрабатывать наличие обязательных полей и их заполнение. HTML текст формы приведен ниже.

add.html:

<HTML>
<HEAD><TITLE>Sign My GuestBook</TITLE></HEAD>

<BODY>
<H2 ALIGN=CENTER>Sign My Guest Book</H2>
<hr>
<FORM METHOD="POST" ACTION="/cgi-bin/guestbook.cgi">
<PRE>
Your name: <INPUT type=text size=60 maxlength=256 name="name">
E-mail address: <INPUT type=text size=60 maxlength=256 name="email">
City: <INPUT type=text size=60 maxlength=256 name="city">
Country: <INPUT type=text size=60 maxlength=256 name="location">
Your Web Page URL: <INPUT type=text size=60 maxlength=256 name="web_url">
Web Page Title: <INPUT type=text size=60 maxlength=256 name="web_title">

Comments:
<TEXTAREA rows=9 cols=51 name="comments"></TEXTAREA>
<br></br>
<INPUT type="submit" value="Submit"> <INPUT type="reset" value="Reset">
</PRE>
</FORM>
</BODY>
</HTML>

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

guestbook.html

<TITLE>Welcome to My Guestbook</TITLE>
<BODY>

<CENTER>
<H1>Welcome to My Guestbook</H1>
</CENTER><P>
<A HREF="add.html"><B>Add Your Name!</A></B><P>
<Hr><P>


<!--My Latest Guest:-->


</BODY>

Обратите внимание на строку-комментарий <!--My Latest Guest:-->. Скрипт при выполнении будет искать данную строку в заготовке и добавлять сюда отзывы посетителей. Последнее введенное сообщение будет отображаться первым. Это избавит посетителя от необходимости перемещаться в конец страницы, для того чтобы увидеть свой отзыв.

ОК, приступим к написанию собственно скрипта. Начнем с инициализации нескольких переменных. Первая - это относительный путь к файлу guestbook.html, говоря проще где искать этот файл. Мы инициализируем переменную $guestbook_file, полагая, что скрипт будет размещен в директории /cgi-bin. Файл guestbook.html будет находиться там же. Если Вы решите разместить файл в другом месте, подправьте путь соответствующим образом.

# Относительный путь к Guestbook.html
$guestbook_file = "../guestbook.html";

Вторая переменная определяет URL файла Guestbook.html. Она позволит организовать отображение посетителю добавленного им отклика. Измените данную переменную в соответствии в адресом Вашего сайта.

# URL файла guestbook.html
$guestbook_url = "http://www.yourdomain.com/guestbook.html";

Так как мы будем отображать дату ввода отклика нам необходимо инициализировать массив названий месяцев.

# Инициализация списка месяцев
@month = ("January", "February", "March", "April", "May", "June", "July",
            "August", "September", "October", "November", "December");

Теперь наш скрипт готов к чтению данных. Данный код взят непосредственно из предыдущей статьи Reading CGI Data мы не будем его подробно разбирать здесь.

# Определяем способ вызова скрипта
if($ENV{'REQUEST_METHOD'} eq "GET"){
$my_data = $ENV{'QUERY_STRING'};
}
else {
$data_length = $ENV{'CONTENT_LENGTH'};
$bytes_read = read(STDIN, $my_data, $data_length);
}

# Получаем набор переданных параметров в виде <Имя параметра>&<значение>
@name_value_array = split(/&/, $my_data);

# Здесь начинаем делать полезную работу. Организуем цикл по массиву параметров
# @name_value_array для разбивки name=value
foreach $name_value_pair (@name_value_array) {
    # Разделяем name=value на имя параметра и его значение
    ($name, $value) = split(/=/, $name_value_pair);

    # Заменяем '+' на ' ' (пустую строку)
    $name =~ tr/+/ /;
    $value =~ tr/+/ /;

    # Преобразуем некоторые шестнадцатеричные значения в символы
    $name =~ s/%(..)/pack("C",hex($1))/eg;
    $value =~ s/%(..)/pack("C",hex($1))/eg;

    # Запоминаем обработанные параметры в ассоциативном массиве.
    $FormData{$name} = $value;
}

Теперь получаем системное время вызовом localtime() и преобразуем его в формат, не вызывающий проблемы 2000 года.

# Получаем дату и время
($Seconds, $Minutes, $Hours, $DayInMonth, $Month, $ShortYear, $DayOfWeek, $DayOfYear, $IsDST) = localtime(time);

# Обеспечиваем совместимость c 2000 годом
$Year = $ShortYear + 1900;

$EntryDate = "$month[$Month] $DayInMonth, $Year";

Теперь все, что надо инициализировано. Можно открыть файл с сообщениями. Делается это очень просто.

open(FILEHANDLE, FILENAME);

Конечно, очень неплохо использовать вызов open() совместно с die, т.к если файл по каким-либо причинам не откроется, вы будете использовать "плохой" дескриптор. Применение die исключает это. При возникновении ошибки скрипт выдает сообщение и завершается. Синтаксис вызова die выглядит так;

open(FILEHANDLE, FILENAME) || die "Couldn't open the file\n";

При успешном выполнении открытия Вы получите дескриптор файла FILEHANDLE. Название дескриптора, как правило, пишут заглавными буквами, чтобы исключить совпадение с зарезервированными словами. Вот как мы открываем файл в скрипте;

# Открытие файла с использованием переменной, определенной в начале скрипта.
open(GUESTBOOK, "$guestbook_file") || die "Can't open GUESTBOOK: $guestbook_file\n";

# Считывание данных из файла для дальнейшей обработки
@guestbook =<GUESTBOOK>;

# Всегда закрывайте файл после использования
close(GUESTBOOK);

Получив содержимое файла отзывов, мы должны записать все обратно в guestbook.html. Если мы обнаруживаем строку '<!--My Latest Guest:-->' в guestbook.html, записываем новый отзыв, тем самым обеспечивая, то что последний отзыв будет вверху страницы. Чтобы открыть файл для записи делаем так:

open(GUESTBOOK, ">$guestbook_file") || die "Can't open GUESTBOOK: $guestbook_file\n";

Теперь надо пройтись по массиву @guestbook, который содержит считанный файл guestbook_file.

foreach $line (@guestbook) {
    # Определяем начало блока куда надо вставлять отзывы
    if($line =~ /<!--My Latest Guest:-->/i) {
        # Добавляем новый отзыв
        # но сначала добавим метку, чтобы в следующий раз вновь можно было ее найти
        print GUESTBOOK "<!--My Latest Guest:-->\n";

        # guestbook HTML файл, т.е теги тоже нужно не забывать
        print GUESTBOOK "<DL>\n";

        if($FormData{'email'}) {
            # Если посетитель ввел e-mail отобразим его как ссылку
            print GUESTBOOK "<DD><I><B><A HREF=\"mailto:$FormData{'email'}\">
            $FormData{'name'}</A></B> - $FormData{'city'}, $FormData{'location'}</I>\n";
        }
        else {
            # Нет t-mail, ничего добавим просто имя
            print GUESTBOOK "<I><B>From:</B> $FormData{'name'}</I><BR>\n";
        }

        if($FormData{'web_url'}) {
            # А может у него и страничка есть своя
            print GUESTBOOK "<DD>Homepage : <A HREF=\"$FormData{'web_url'}\">$FormData{'web_title'}</A>\n";
        }
        # Непосредственно текст отзыва
        print GUESTBOOK "<ul><p>\n";
        print GUESTBOOK "$FormData{'comments'}\n";
        print GUESTBOOK "</ul>\n";

        # Дата получения отзыва
        print GUESTBOOK "<p><I><font size=2>\n";
        print GUESTBOOK "signed on $EntryDate\n";
        print GUESTBOOK "</I></font>\n";

        # Усе, вставим несколько закрывающихся тегов
        print GUESTBOOK "</DL>\n";
        print GUESTBOOK "<HR>\n";
    }
    else {
        # Это уже не первый отзыв, просто добавим его обратно в файл
        print GUESTBOOK "$line";
    }
}
close(GUESTBOOK);

Файл guestbook.html обновлен, теперь выведем посетителю сообщение об успешном внесении его отклика в книгу.

print <<"EOF"
<H1>Your GuestBook Entry has been Submitted\!</H1>
Your guestbook entry has been successfully added to the
<A HREF="$guestbook_url">guestbook</A>.
You may need to click reload to view your guestbook entry.<P>
EOF

Текст выше использует текущий документ. Если вы хотите вывести сразу несколько строк, то нет необходимости каждый раз вызывать print. Если применить << и имя строки, то будет напечатано все до тех пор, пока не будет обнаружено имя строки (в данном случае EOF).

Ну вот и все. Скрипт готов. Конечно он далек от совершенства, но это хорошая основа для дальнейшей работы. Пути усовершенствования:

  1. Создавать файл guestbook.html, если он найден;
  2. Ввести проверку ввода данных в обязательные поля (как минимум ввод имени посетителя );
  3. Добавить переадресацию, чтобы посетитель не щелкал на ссылку для возврата к guestbook.html после ввода отзыва;
  4. Добавить блокировку файла guestbook.html, чтобы исключить повреждение файла при доступе нескольких посетителей.

Ниже приведен полный код скрипта:

#!/usr/local/bin/perl

#===============================
# A Simple Guestbook Script
# Copyright 1999, Emmie P. Lewis
# Created 07/09/99
#===============================
# This script shows how to write
# a guestbook script.
#===============================

print "Content-type:text/html\n\n";

# Initialize File Pathnames

# Relative path of Guestbook.html
$guestbook_file = "../guestbook.html";

# URL to guestbook.html
$guestbook_url = "http://localhost/guestbook.html";

# Initialize list of months
@month = ("January", "February", "March", "April", "May", "June", "July",
            "August", "September", "October", "November", "December");


# Read in the CGI Data, no matter which method was used
# (If you're unsure what this code does, see 'Reading CGI Data'
# http://perl.about.com/library/weekly/aa052499.htm)

if($ENV{'REQUEST_METHOD'} eq "GET"){
$my_data = $ENV{'QUERY_STRING'};
}
else {
$data_length = $ENV{'CONTENT_LENGTH'};
$bytes_read = read(STDIN, $my_data, $data_length);
}

# Let's load it into something we can use
@name_value_array = split(/&/, $my_data);

# Here's where we do the actual work. We're going to cycle
# through @name_value_array to decode the name=value pairs
foreach $name_value_pair (@name_value_array) {
    # Split the name=value pair in your HTML form data
    ($name, $value) = split(/=/, $name_value_pair);

    # Now, replace '+' with ' '
    $name =~ tr/+/ /;
    $value =~ tr/+/ /;

    # Next, we'll translate any hex values back into characters
    $name =~ s/%(..)/pack("C",hex($1))/eg;
    $value =~ s/%(..)/pack("C",hex($1))/eg;

    # Finally, we'll load the variables into an associative array
    # so we can use it when we need it.
    $FormData{$name} = $value;
}

# Get the date and time information
($Seconds, $Minutes, $Hours, $DayInMonth, $Month, $ShortYear, $DayOfWeek,
$DayOfYear, $IsDST) = localtime(time);

# Fix the year to keep it Y2K compliant, as described in 'Perl and Y2K'
# http://perl.about.com/library/weekly/aa070299.htm
$Year = $ShortYear + 1900;

$EntryDate = "$month[$Month] $DayInMonth, $Year";

# OK, now open the current guestbook file and read it in
open(GUESTBOOK, "$guestbook_file") || die "Can't open GUESTBOOK: $guestbook_file\n";
@guestbook =<GUESTBOOK>;
close(GUESTBOOK);

# Open it again so that we can add the current guest to the file
open(GUESTBOOK, ">$guestbook_file") || die "Can't open GUESTBOOK: $guestbook_file\n";
foreach $line (@guestbook) {
    # Check to see if we're at the beginning of the guest book
    if($line =~ /<!--My Latest Guest:-->/i) {
        # We are, so add our latest guest
        # Start by adding the guestbook header to the file, so we can find it next time
        print GUESTBOOK "<!--My Latest Guest:-->\n";

        # The guestbook is an HTML file, so we'll have to add the tags too
        print GUESTBOOK "<DL>\n";

        if($FormData{'email'}) {
            # if there's an email address, let's add it as a link
            print GUESTBOOK "<DD><I><B><A HREF=\"mailto:$FormData{'email'}\">
            $FormData{'name'}</A></B> - $FormData{'city'}, $FormData{'location'}</I>\n";
        }
        else {
            # otherwise, just add their name
            print GUESTBOOK "<I><B>From:</B> $FormData{'name'}</I><BR>\n";
        }

        if($FormData{'web_url'}) {
            # If they included their web url, add the link
            print GUESTBOOK "<DD>Homepage : <A HREF=\"$FormData{'web_url'}\">$FormData{'web_title'}</A>\n";
        }
        # add the comments
        print GUESTBOOK "<ul><p>\n";
        print GUESTBOOK "$FormData{'comments'}\n";
        print GUESTBOOK "</ul>\n";

        # add the date
        print GUESTBOOK "<p><I><font size=2>\n";
        print GUESTBOOK "signed on $EntryDate\n";
        print GUESTBOOK "</I></font>\n";

        # finish up
        print GUESTBOOK "</DL>\n";
        print GUESTBOOK "<HR>\n";
    }
    else {
        # just print the existing line to the updated file
        print GUESTBOOK "$line";
    }
}
close(GUESTBOOK);

# Tell our new guest they've been added, and let them see their entry
print <<"EOF"
<H1>Thanks\!</H1>
Your entry has been added to the <A HREF="$guestbook_url">guestbook</A>.
You may need to click reload to view your guestbook entry.<P>
EOF

P.S. От переводчика

Оригинальный текст статьи расположен на сайте http://www.about.com/.
Если у Вас возникли пожелания, замечания, предложения я буду рад получить их по адресу mgoblin@mail.ru
Спасибо, желаю Вам успехов, Mike Goblin.

Автор перевода: Mike Goblin
Информация взята с сайта Masters of CGI.Perl


© журнал принадлежит Web Creation
по всем вопросам обращаться А. Кузьмин