PHP Delphi CSS HTML JavaScript Perl API ASP MySQL XML С++ VBasic WEB разработка *NIX CouchDB Hack Python
Главная Статьи Perl Дискуссионный форум (perl+mySQL)
Главная
 Главная  Контакты
 
Программинг
Статьи Книги ЧаВО
 
xBOOKi
Fresh Books Операционки Сети
 
Поиск
-------
 
Counters
Яндекс цитирования
Rambler's Top100
-------
 
CryptDisk.4h
Программа которая позволяет создать виртуальный шифрованный логический диск.

cryptdisk.4hack.com

-------
 
 

Дискуссионный форум (perl+mySQL)

Алексей Литвинюк

Форум — это неотъемлемая часть любого серьезного сайта в Интернет. Веб-мастеру очень важно предоставить своему посетителю возможность задать вопрос и получить на него ответ по заданной теме. Это делает ваш сайт более интерактивным и более содержательным. Следовательно, сайт становится привлекательнее не только для тех, кому нужна помощь, но и кто хочет выразить свое мнение, поспорить или просто помочь нуждающимся.

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

Итак, после долгих и мучительных раздумий вы все же решились писать форум своими силами. Первой предстает проблема выбора технологии. На ум приходят три варианта: первый — это Java-апплеты, второй — php, и третий — CGI.

Java-апплетами можно воспользоваться только совместно с CGI или JDBC. И не факт, что в браузер пользователя встроена поддержка Java или просто она отключена, как опция. Поэтому этот вариант можно опустить.

Теперь предстоит выбрать: php или CGI? У каждой из этих технологий есть свои преимущества и недостатки. Однако остановимся на последнем. Для CGI воспользуемся уже ставшим просто родным языком для написания CGI-скриптов — языком perl.

Что касается СУБД, то здесь выбор большой. Это может быть любая СУБД, которая имеет драйвер DBD. К примеру, mySQL.

Перед тем, как перейти непосредственно к написанию, необходимо определиться с форматом таблиц базы данных. Любой форум должен подразделяться на обсуждаемые темы, в которых в свою очередь есть свои подтемы (вопросы). Их и обсуждают участники форума. Создавать на каждый тематический форум отдельную таблицу было бы очень расточительно, поэтому надо найти альтернативное решение. Для списка названий тематических форумов и их идентификаторов создадим отдельную таблицу, предварительно создав новую базу данных. Пусть имя базы данных будет FORUM, а таблицу назовем FIDS (Forum's IDentificatorS):

CREATE TABLE FIDS(FID CHAR(5), NAME CHAR(25));

Имеем два поля: первое — FID, идентификатор форума со строковым типом и размером в 5 символов, и второе — NAME, имя соответствующее идентификатору форума, размер этого поля 25 символов. Теперь добавим туда несколько записей:

INSERT INTO FIDS VALUES('01','Основной');
INSERT INTO FIDS VALUES('02','Программирование на perl');
INSERT INTO FIDS VALUES('03','Служебный');

Вторая таблица должна содержать записи, в которых будут располагаться сообщения из всех форумов. Вот пример придуманной мной структуры этой таблицы:

CREATE TABLE MESSAGES (ID CHAR(10), FID CHAR(10), FROM_N CHAR(45), TO_N CHAR(45), SUBJ CHAR(70), EMAIL CHAR(70), MSG_TEST TEXT, DATETIME CHAR(20));

где ID — идентификатор записи (сообщения);
FID — идентификатор форума, куда было помещено это сообщение;
FROM_N — имя пользователя, который отправил сообщение;
TO_N — имя адресата сообщения;
SUBJ — тема сообщения (причем для того, чтобы отличать темы исходного сообщения от ответов, можно в начале темы вставлять, к примеру, "0" и потом делать проверку);
EMAIL — электронный адрес отправителя;
MSG_TEXT — непосредственно текст сообщения;
DATETIME — это время и дата в Unix-формате;

Вы можете преобразовать эту таблицу, добавив то, что вам необходимо.

В результате мы получили реляционную базу данных, состоящую из двух таблиц, связанных по полю FID. Почему мы вынесли названия форумов в отдельную таблицу, станет понятно далее.

Существуют форумы, для участия в которых вам необходимо сначала зарегистрироваться, чтобы в дальнейшем участвовать в дискуссиях. Это тот же www.talk.ru. Но это специализированный сайт. Мы же пытаемся спроектировать форум для собственного сайта, поэтому регистрация нужна только для тех, кто не боится, что посетитель не захочет проходить процедуру регистрации ради того, чтобы задать один единственный вопрос. Для регистрации нужно выделить отдельную таблицу. В ней будут храниться основные сведения о зарегистрированных пользователях, их пароли и идентификаторы. Чтобы не позволить не зарегистрированным пользователям пользоваться форумом, есть два способа.

Первый — записать ему cookie, где будут храниться его идентификатор и пароль на длительный срок. Считывая их при попытке входа в форум и проверяя на соответствие с данными в таблице, допускаем зарегистрированного пользователя и обновляем его cookie (хотя это и не обязательно).

Второй — это каждый раз при попытке входа в форум запрашивать пользовательский логин и пароль, после чего записывать ему временный cookie (если требуется абсолютная проверка при каждом обновлении страниц форума).

Теперь что касается непосредственно кода скрипта. Я за долгое время работы с CGI понял, что использование одного файла-скрипта является наиболее оптимальным, нежели написание отдельного скрипта для выполнения каждой функции. Для того чтобы разделить функции внутри одного скрипта, достаточно передавать ему дополнительный параметр с номером выполняемого действия. Важно также то, как вы его назовете. Не надо придумывать явное имя, по которому можно с легкостью определить, что этот параметр делает. Назовите его, к примеру, "a"(Action). Каждая цифра (значение параметра "a") будет обозначать какое-то действие:
1 — вывести сообщения форума;
2 — добавить сообщение в форум;
3 — ответить на сообщение в форуме.

Для того чтобы определять, сообщения какого форума будем выводить, введем дополнительный параметр. Он будет иметь значение идентификатора форума. Тут нам и пригодилось то выделение отдельной таблицы с идентификаторами форумов. Это освобождает от передачи имени форума в качестве параметра скрипта, что было бы очень не удобно. Назовем это параметр "fn" (Forum Number).

Таким образом, если нам надо вывести сообщения из форума "Основной", зная, что его идентификатор равен 1, то скрипту мы передаем следующую строчку параметров:

"a=1&fn=1"

Сразу оговорюсь насчет метода передачи параметров скрипту. В случае, когда вы хотите вывести форум, то оптимальным вариантом будет использование метода GET. Почему? Просто ссылку на форум проще будет оформить обычным тегом , а не формой. Т.е. для того, чтобы вызвать "Служебный" форум, просто вставляем в HTML-документ следующую ссылку:

Перейти к "Служебному" форуму

При ответе на сообщения возникает необходимость передавать скрипту идентификатор сообщения, на которое пользователь пожелал ответить. Следует ввести новый параметр с именем, например, mid (Message IDentificator). 
Пример строки запроса (параметров) скрипту:

"a=3&fn=1&mid=2"

Т.е. мы говорим скрипту, что мы хотим ответить (a=2) в форуме с идентификатором 1(fn=1) на сообщение с идентификатором 2(mid=2).

В ответ на этот запрос скрипт должен построить следующий запрос к базе данных:

SELECT * FROM MESSAGES WHERE (ID = 2);

Если вам не нужны все поля из этой таблицы, то вместо * можно в круглых скобках указать список полей через запятую, которые вам нужно выбрать. После выборки сообщения скрипт должен сформировать HTML-документ. В нем должна присутствовать форма, в которой уже будут заполнены некоторые поля данными из базы данных. Плюсом к вашему форуму может стать квотинг текста. Квотинг — это пометка текста инициалами автора. Это значит, что перед каждой строчкой нужно вставить что-то такое: "AL>", где AL — это инициалы автора. Квотить нужно только то сообщение, на которое собираются отвечать. Вот как это выглядит:

AL> Кто-нибудь уже занимался программированием систем дистанционного обучения?
AL> Посоветуйте чего бы почитать на эту тему?

А ниже пользователь, отвечающий на это сообщение, будет писать свой ответ. Такой подход позволяет легко ориентироваться, кто что писал.

После вывода этого документа пользователь отвечает на сообщение, нажимает кнопку “отправить”. Форму нужно связать с функцией добавления сообщения (a=2). Это осуществляется при помощи скрытых полей:

Это что касается метода GET при выводе форума и ответе на сообщение. По-другому дело обстоит, когда пользователь производит добавление сообщения в форум. В этом случае лучше использовать метод POST: пользователь не будет смущен множеством непонятных символов в строке ввода адреса; этот метод более приспособлен к отправке скрипту больших объемов данных. Позволю себе напомнить, что при использовании метода POST параметры в скрипте необходимо считывать со стандартного устройства ввода (STDIN), а не из переменной окружения QUERY_STRING, как с методом GET.

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

Очень полезный момент при добавлении сообщения — это возможность получать ответы на свой вопрос по электронной почте, например, когда пользователь по какой-либо причине не может вовремя зайти на форум, но очень сильно ждет ответа на свой вопрос. Для этого в форме ввода сообщения добавьте элемент checkbox примерно так:

Отсылать сообщения, адресованные мне

В базе данных вам нужно будет либо добавить новую таблицу, либо добавить новое поле в таблицу сообщений или просто установить флажок в начале одного из полей (это может быть 0 или 1 в начале темы сообщения). И при каждой операции добавления сообщения нужно проверять наличие флажка, и если он установлен, то посылать этот ответ на адрес электронной почты пользователю. Этот электронный адрес и флажок находятся в том же сообщении, на которое отвечает пользователь. Реализация этой опции не должна вызвать у вас затруднения. Теперь перейдем к вопросу реализации самого скрипта. Первое, что хотелось бы отметить, — это шаблоны. Сейчас мало кто использует эту технологию. Но в CGI-программировании она просто не заменима. Без шаблонов попытка изменить внешний вид HTML-документов и форм в них вынуждает делать изменения в самом скрипте. Этого можно избежать, пользуясь шаблонами. Вы пишите любой код на HTML, параллельно вставляя специальные теги в те места, где должны находиться переменные, которые предварительно будут заменяться скриптом на значения переменных. Приведу пример шаблона:


%%vmForumName%%


%%vmMessages%%




В этом шаблоне текст, заключенный в %%, и есть те самые специальные теги. В нашем случае vmForumName будет заменен на имя форума, а vmMessages — на список сообщений. Причем список сообщений должен быть сгенерирован на основании склеивания предварительно заполненных шаблонов сообщения. Это означает, что нужно описать еще один шаблон для сообщений:



#%%vMsgID%%%%vMsgDateTime%%


%%vSubj%%From: %%vFrom%%To: %%vTo%%


%%vText%%

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

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

Приведу пример кода:

sub put_template {
my($tpl_n) = $_[0];
my($fn);
$fn = $VAR{$tpl_n};
if (!open (TPL, "$fn"))
{
print "Content-type: text/html\n\n",
$q->start_html("$lng1{'2'}"),
$q->h1("Error: $lng1{'1'} шаблон"),
$q->end_html;
die;
}
while ()
{
chomp($_);
$_ =~ s#%%([^>%]+)%%#$HTML_VAR {}#g;
print "$_"."\n";
}
close (TPL);
}

sub parse_template {
my($tpl_n) = $_[0];
my($fn,$r_s);
$fn = $VAR{$tpl_n};
if (!open (TPL, "$fn"))
{
print "Content-type: text/html\n\n",
$q->start_html("$lng1{'2'}"),
$q->h1("Error: $lng1{'1'} шаблон"),
$q->end_html;
die;
}
while ()
{
chomp($_);
$_ =~ s#%%([^>%]+)%%#$HTML_VAR{}#g;
$r_s.= "$_"."\n";
}
close (TPL);
return $r_s;
}

Первая подпрограмма выводит результат на STDOUT, а вторая возвращает значение.

Я сознательно не захотел объединять их в одну подпрограмму.

Подпрограммы пользуются значениями двух хешев: %VAR и %HTML_VAR. В первом хранятся соответствия названий (альясов) шаблонов с именами файлов этих шаблонов, а во втором — переменные. Вот как они выглядят:

%VAR = (
'msg_tpl' => './tpl/message.tpl',
'main_tpl' => './tpl/main.tpl'
);

%HTML_VAR = (
'vmForumName' => '',
'vFrom' => ''
);

Перед выводом шаблона мы должны переопределить все переменные, которые используются в данном шаблоне:

$HTML_VAR{'vmForumName'} = "Основной";
put_template('main_tpl');

Шаблон можно создать в любом WYSIWYG-редакторе, вставляя, где необходимо, специальные теги, как простой текст.

Важным моментом является выбор пакета для работы с CGI на perl. Их существует масса (www.cpan.org). Однако огромной популярность по праву обладает CGI.pm, разработанный Линкольном Штейном. Но зачем? Вы ведь можете написать свою библиотеку подпрограмм и работать с ней. У этого способа есть множество недостатков. Первый — это ошибки, второй — это то, что такие крупные пакеты, как CGI.pm, постоянно совершенствуются и стремятся за новшествами, которые вводит W3C, да и стоит ли изобретать велосипед?:-/

Если вы пишете программный продукт и хотите, чтобы им могли пользоваться не только вы, то надо обеспечить его как можно большим числом настроек. Под настройками в данном случае понимается инициализация переменных в начале скрипта. Это могут быть: количество выводимых на экран сообщений; имя базы данных, с которой будем работать; IP-адрес СУБД; различные флажки, к примеру, на предмет удаления старых писем. Это позволит вашему скрипту быть как можно гибким при переносе на другой сервер.

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

Хотелось бы отметить еще один момент. После добавления будет лучше, я думаю, вывести сразу список сообщений вместе с добавленным сообщением. Это можно сделать при помощи добавления в заголовок HTML опции Refresh:

Content-type: text/html
Refresh: 0;url=ваш_скрипт?a=1&fn=1

Параметр url указывает, на что сменить адрес, 0 — это время задержки перед тем, как сменить текущий адрес. Хотя это можно было бы сделать и при помощи JavaScript:

Т.е. при загрузке страницы переходим на новый адрес. Это позволит пользователю сразу увидеть, что его сообщение было внесено в базу данных.

Кстати, насчет баз данных. SQL-запросы надо строить на основании возможностей СУБД. Если вы планируете переносить свою программу на разные СУБД, то нужно поддерживать ANSI SQL. Однако это тоже не всегда помогает. Например, в mySQL я не нашел вложенных запросов. Так что лучше формировать несколько простых, нежели один, но сложный. Тем более что небольшие запросы отрабатывают намного быстрее. К этому также относится и проблема выборки больших объемов. Лучше и проще пытаться сформировать запросы, как можно больше ограничивающие рамки результативных данных. Т.е. ставить четкое условие, потому как постоянная передача больших объемов данных может существенно замедлить работу. А это никак не повысит имидж вашего форума.

Теперь, кажется, единственное, что осталось посоветовать — это побыстрее приступать к работе над своим форумом. Я наверняка затронул не все моменты в программировании форумов, однако, я постарался сделать акценты на самых важных из них. В статье сознательно приводилось минимум исходного кода. Если у вас возникли какие-нибудь вопросы или замечания, пишите.

Источник: http://www.nestor.minsk.by/kg

 



Свежее
Резервное копирование rsync-ом
DNS Amplification (DNS усиление)
Алгоритм Шинглов — поиск нечетких дубликатов текста
Metasploit Framework. Обзор
Использование CouchDB
-------



 
Copyright © 2003-2009   Frikazoid.
Rambler's Top100