On-Line Библиотека www.XServer.ru - учебники, книги, статьи, документация, нормативная литература.
       Главная         В избранное         Контакты        Карта сайта   
    Навигация XServer.ru






 

Практические примеры программирования cgi-скриптов на Perl: форум

OlegTr

Форумы в Интернете можно встретить сплошь и рядом.Ни один уважающий себя сайт не обходится без них. Форум дает возможность узнать мнение посетителей о сайте и о том,что они думают об авторе и о его творениях :). Форум,пример которого я здесь приведу не очень сложный,но он обеспечивает все необходимые функции.Для лучшего понимания имеет смысл разбить его на несколько частей,объяснить каждую в отдельности,а затем объединить все вместе.

Данный форум состоит из следующих частей:

Начнем не с главной страницы,потому что она обобщает всю информацию,а с середины-добавления нового топика.

Добавление нового топика.

Сначала в директории cgi-bin веб-сервера создадим каталог html,куда будут записываться все сообщения. Сразу оговорюсь,что все сообщения пишутся в html-файл:сначала топик и сообщение,затем к нему дописываются ответы. По ходу дела все будет понятно.
Сгенерируем форму для добавления новой темы и сообщения.

#!/usr/local/bin/perl
#Webforum.cgi version 1.01
$request=$ENV{'REQUEST_METHOD'};
$content=$ENV{'CONTENT_LENGTH'};

$cgi="url/cgi-bin";
$url="url/cgi-bin/html";
$dir="/usr/local/apache/cgi-bin/html";

print "Content-type:text/htmlnn";
print <<HTML;
<html><head><style>a:link {text-decoration:none; }</style></head><body>
<h3 align=center><font color="0000ff">New topic</font></h3>
<p align=right><a href="$cgi/webforum.cgi"><font face="ferdana" size=3>
<b>Home</b></font></a>
<p><form action="$cgi/webforum.cgi" name="newtop" method="GET">
<table width=60% align=center bgcolor="e6e8fa">
<tr><td> 
<tr><td><b>Your nick:</b><td><input type="text" name="nick" size=20>
<tr><td><b>Topic name:</b><td><input type="text" name="theme" size=20>
<tr><td><input type="hidden" name="action" value="ok">
<tr><td colspan=2> <b>Message:</b><p>  
<textarea cols=40 rows=15 name="post" wrap="virtual"></textarea>
<tr><td colspan=2><input type="submit" value="Submit"></table>
HTML

Если данные введены в форму получаем их и декодируем.

@pairs = split(/&/, $query);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$name =~ s///g;
$name =~ s/<([^>]|n)*>//g;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s///g;
$value =~ s/</</g;
$value =~ s/>/>/g;
$value =~ s/cM/ /g;
$value =~ s/|/ /g;
$value =~ tr/ / /s;
$value =~ s/<([^>]|n)*>//g;
$value =~ s/"/"/g;
$value=~s/(http://+S)/<A href="$1">$1</A>/g;
$input{$name} = $value;
}

$nick=$input {'nick'};
$theme=$input {'theme'};
$message=$input {'post'};

#Create new topic.

#Открываем каталог и читаем его содержимое.Файлы в каталог записываются в виде #001.html,002.html и т.д.То есть,каждый вновь записываемый файл,увеличивается #на единицу.Это делается следующим образом.

opendir (DIR,"$dir"); while (@mes=readdir (DIR)) { foreach $mes(@mes) { $count=@mes; $count++; $page="00".($count-2); }

# ($count-2)-это для того,чтобы не считать подкаталоги типа "." и "..". # Проверяем,не являются ли поля формы пустыми.Если нет-открываем файл на запись # и пишем информацию.

if ($nick ne "" && $theme ne "" && $message ne "") { open (FILE,">$dir/$page.html"); print FILE "<html><head><style>a:link {text-decoration:none; } </style><title>$theme</title>n"; print FILE "<meta name="author" content="$nick"></head>n"; print FILE "<body bgcolor="f6f8fa">n"; print FILE "<p align=right><a href="$cgi/webforum.cgi?action=reply&file=$page.html">n"; print FILE "<font face="ferdana" size=3><b>Post reply</b></font></a>n"; print FILE " <a href="$cgi/webforum.cgi"><font face="ferdana" size=3><b>Home</b></font></a><p>n"; print FILE "<table width=90% cellpadding=0 cellspacing=0 border=1>n"; print FILE "<tr><td align=center width=150 bgcolor="D5E6E1"><font face="Arial" size=2 color="808080">Author</font>n"; print FILE "<td bgcolor="D5E6E1"><font face="serif" size=2 color="0000ff">Topic:</font>n"; print FILE "<font face="serif" size=2 color="ff0000">$theme</font></td></tr>n"; print FILE "<tr><td rowspan=2 bgcolor="D5E6E1" align=center><font face="serif" size=3 color="ff0000">$nick</font></td>n"; print FILE "<td bgcolor="e6e8fa" height=30><font face="serif" size=1 color="000080">Posted:",scalar localtime,"</font></td></tr>n"; print FILE "<tr><td bgcolor="f7f7f7"><font face="serif" size=2 color="000080">$message</font></td></tr></table>n"; close (FILE); } else {

#Если одно из полей формы осталось пустым-выдаем ошибку.Это делается для того,чтобы # не создавать пустые файлы,не содержащие информации.Perl'у все равно,что писать :)

print "Content-type:text/htmlnn"; print <<HTML; <p>  <p>  vp>  <body bgcolor="e6e8fa"> <h3 align=center>Sorry,you didn't enter your nick or message! </h3> <p><center><b>Please,go back and try again</b> <p><a href="$cgi/webforum.cgi?action=newtop"><font face="ferdana" size=3> <b>Back</b></font></a> </center> HTML exit; } } closedir (DIR); }

# Если все прошло нормально,выносим пользователю благодарность.Новый топик создан.

print "Content-type:text/htmlnn"; print <<HTML; <p>  <p>  <p>  <body bgcolor="e6e8fa"> <h3 align=center>Thank you,<font color="0000ff">$nick!</font></h3> <p><center><b>Your message is added.</b> <p><a href="$cgi/webforum.cgi"><font face="ferdana" size=3> <b>View topics</b></font></a></center> HTML </BODY> </HTML> HTML

Добавление ответа на топик.

Добавление ответа почти ничем не отличается от добавления топика,единственное отличие- нужно передать адрес страницы,чтобы скрипт знал,куда писать ответ.А он содержится в файле топика.Если посмотреть чуть выше,можно увидеть ссылку <a href="$cgi/webforum.cgi?action=reply&file=$page.html">Post reply</a> В ней и передается адрес страницы.
Генерируем форму:


# Сначала читаем файл в массив.Это делается для того,чтобы поместить его во фрейм ниже формы # на тот случай,если кто-то захочет вставить цитату из предыдущих сообщений.

$page=$input {'file'}; open (FILE,"$dir/$page"); @data=<FILE>; close (FILE); print "Content-type:text/htmlnn"; print <<HTML; <html><head><style>a:link {text-decoration:none; }</style></head><body> <h3 align=center><font color="0000ff">Post reply</font></h3> <p align=right><a href="$cgi/webforum.cgi"><font face="ferdana" size=3><b>Home</b></font></a> <p><form action="$cgi/webforum.cgi" name="reply" method="GET"> <table width=60% align=center bgcolor="e6e8fa"> <tr><td> <br><b>Your nick:</b><td>vinput type="text" name="nick" size=20> <tr><td><input type="hidden" name="type" value="reply"> <tr><td><input type="hidden" name="action" value="ok"> <tr><td><input type="hidden" name="file" value="$page"> <tr><td colspan=2> <b>Message:</b><p>   <textarea cols=40 rows=15 name="post"></textarea> <tr><td colspan=2><input type="submit" value="Submit"></table> <p><center><iframe src="$dir/$page" width=90% height=300></iframe></center> HTML #Reply to topic.

# Снова проверяем,чтобы поля формы не были пустыми.Если все в порядке,открываем файл, # содержащий топик на добавление и дописываем ответ.

if ($nick ne "" && $message ne "" ) { open (FILE,">>$dir/$page"); print FILE "<table width=90% cellpadding=0 cellspacing=0 border=1>n"; print FILE "<tr><td rowspan=2 bgcolor="f7f7f7" align=center width=150><font face="serif" size=3 color="0000ff">$nick</font></td>n"; print FILE "<td bgcolor="e6e8fa" height=30><font face="serif" size=1 color="000080">Posted:",scalar localtime,"</font></td></tr>n"; print FILE "<tr><td bgcolor="f7f7f7"><font face="serif" size=2>$message</td></tr></table>n"; close (FILE); close (FILE); } else {

# Если одно из полей осталось пустым-выдаем ошибку.

print "Content-type:text/htmlnn"; print <<HTML; <p>  <p>  <p>  <body bgcolor="e6e8fa"> <h3 align=center>Sorry,you didn't enter your nick or message! </h3> <p><center><b>Please,go back and try again</b> <p><a href="$cgi/webforum.cgi?action=reply&file=$page.html"><font face="ferdana" size=3><b>Back</b></font></a> </center> HTML exit; }

# Снова выносим благодарность посетителю.Ответ добавлен.

print "Content-type:text/htmlnn"; print <<HTML; <p>  <p>  <p>  <body bgcolor="e6e8fa"> <h3 align=center>Thank you,<font color="0000ff">$nick!</font></h3> <p><center><b>Your message is added.</b> <p><a href="$cgi/webforum.cgi"><font face="ferdana" size=3> <b>View topics</b></font></a></center> HTML </BODY> </HTML> HTML

Главная страница.

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

Данные на экран выводятся в виде html-таблицы.

print "Content-type:text/htmlnn";
print <<HTML;
<html><head><title>Webforum ver1.01</title>
<style>a: {text-decoration:none; } </style></head>
<body bgcolor="e6e8fa">
<p> 
<p><h2 align=center><font color="0000ff">Webforum</font></h2>
<p align=right><a href="$cgi/webforum.cgi?action=newtop">
<font face="ferdana" size=3><b>New topic</b></font></a>
<p><table width=700 cellpadding=0 cellspacing=0 border=1>
<tr bgcolor="D5E6E1"><td align=center width=300 height=50>
<font face="arial" size=2 color="0000ff">Topic name</font></td>
<td align=center width=150 height=50><font face="arial" size=2 color="0000ff">
Topic starter</font></td>
<td align=center width=50 height=50><font face="arial" size=2 color="0000ff">Replies</font></td>
<td align=center width=200 height=50><font face="arial" size=2 color="0000ff">Last post</font></td></tr>
HTML

# С этим,думаю,все понятно.А теперь более подробно о том,как получить всю эту информацию. # Открываем каталог и читаем сообщения в массив.

opendir (DIR,"$dir"); while (@mes=readdir(DIR)) { foreach $mes (@mes) {

# Каждый файл в каталоге открываем и читаем в массив.

if (!-d "$dir/$mes" && "$mes" ne "." && "$mes" ne "..") { $mtime=localtime((stat("$dir/$mes"))[9]); open (FILE,"$dir/$mes"); @lines=<FILE>; close (FILE);

# Теперь в каждом файле с помощью регулярных выражений ищем тему топика,имя автора топика # и количество ответов.

foreach $line (@lines) { if ($line=~ /<title>(.*?)</title>/is) { $title=$1; } if ($line=~ /content="(.*?)"/is) { $name=$1; }

# Количество ответов помещаем в массив reply,отнимая единицу,так как первое сообщение-это # сообщение автора топика.

if ($line=~ /^<table(s*)(.*?)>$/i) { $reply=$1; push (@reply,$reply); $char=@reply-1; } }

# Печатаем данные в таблицу,после каждой итерации очищая массив reply,чтобы ответы на # каждый топик не складывались после каждой итерации.

print <<HTML; <tr bgcolor="f7f7f7"><td height=30><a href="$url/$mes"> <font face="serif" size=2>$title</font></a></td> <td align=center height=30><font face="serif" size=2>$name</font></td> <td height=30 align=center>$char</td> <td height=30 align=center><font face="serif" size=2>$mtime</font></td></tr> HTML splice (@reply); } } } print "</table>n"; closedir (DIR);

Ну вот,вроде бы и все.

Полный листинг форума вы можете посмотреть здесь,а пример работы- здесь,на страницах этого сайта.

Конечно,я не реализовал все возможности.Можно добавить регистрацию пользователя,возможность редактирования сообщений и т.д.В дальнейшем я планирую доработать этот форум и сделать его более продвинутым. В данный момент моей целью было объяснить,как это работает.Если я достиг ее-буду рад.

Если вам понравился этот материал-оставьте свой комментарий.

Кстати,более крутой форум написанный на PHP с использованием базы данных MySQL,вы можете посмотреть и скачать в Каталоге скриптов.В нем я реализовал все возможности,не реализованные здесь.Скоро я опишу процесс создания такого форума.



Литература по Perl