Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад] [Содержание] [Дальше]

Практика применения Perl, PHP, Apache, MySQL для активных Web-сайтов

(С) Александр Фролов, Григорий Фролов, 2002

9. Web-узел симпозиума

9. Web-узел симпозиума.. 1

База данных Web-узла симпозиума.. 2

Пожелания и предложения. 3

Предложения о сотрудничестве. 3

Участники симпозиума. 4

Запись на госпитализацию.. 4

Доклады и докладчики. 4

Разделы Web-узла симпозиума.. 5

Бланк направления на госпитализацию.. 8

Фреймы бланка. 8

Сценарий печати бланка. 9

Страница пожеланий и предложений. 9

Форма отправки сообщения. 10

Программа comment.pl 11

Поиск участников симпозиума. 12

Форма поиска участников. 13

Программа заполнения формы поиска. 14

Программа выполнения поиска. 15

Шаблон страницы с результатами поиска. 17

Поиск докладов. 18

Форма поиска докладов. 20

Программа поиска докладов. 21

Администрирование Web-узла симпозиума.. 22

Загрузка списка участников симпозиума. 23

Форма для загрузки файла. 25

Программа загрузки файла списка участников симпозиума. 26

Программа сохранения списка участников в базе данных. 27

Загрузка списка докладов. 29

Загрузка файлов ангиограмм и других файлов. 32

Просмотр сообщений посетителей Web-узла симпозиума. 36

 

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

В этой главе мы расскажем Вам о некоторых аспектах использования Web-технологий на IV международном симпозиуме «Сердечно-сосудистая и интервенционная радиология», проходившем в Москве осенью 2001 года. В частности, будут описаны программные решения Web-узла http://forum.angio.ru (рис. 9-1).

Рис. 9-1. Главная страница Web-узла симпозиума

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

База данных Web-узла симпозиума

База данных симпозиума была создана с применением СУБД Microsoft SQL Server 2000, работающей под управлением операционной системы Microsoft Windows 2000. Тем не менее, мы использовали только такие возможности СУБД Microsoft SQL Server 2000, которые доступны и в MySQL. При необходимости Вы сможете использовать решения, описанные в этой главе, в среде ОС Linux и других операционных систем, для которых есть реализация MySQL и Perl.

Все таблицы базы данных Web-узла симпозиума, имеющей название angio, перечислены в табл. 9-1.

Таблица 9-1. Таблицы базы данных angio

Таблица

Описание

comment

Пожелания и предложения посетителей Web-узла симпозиума

cooper

Предложения о сотрудничестве

members

Список участников симпозиума

record

Запись на госпитализацию

reporters

Список докладчиков

В листинге 9-13 находится сценарий SQL, с помощью которого можно создать базу данных angio, использовав для этого программу Enterprise Manager.

Листинг 9-13 Вы найдете в файле chap09\admin.angio\angio_base.sql на прилагаемом к книге компакт-диске.

Рассмотрим структуру таблиц базы данных angio.

Пожелания и предложения

В таблице comment хранится информация, оставленная посетителями узла симпозиума на странице Пожелания и предложения (рис. 9-6). Структура таблицы описана в табл. 9-2.

Таблица 9-2. Таблица comment

Поле

Тип данных

Описание

id

int

Уникальный идентификатор записи

name

varchar(255)

Фамилия, имя и отчество посетителя

city

varchar(255)

Город, в котором проживает посетитель

profession

varchar(255)

Профессия посетителя

email

varchar(255)

Адрес электронной почты посетителя

msg

varchar(2000)

Сообщение, оставленное посетителем

add_date

datetime

Дата и время добавления записи

Ниже мы привели сценарий SQL, при помощи которого можно создать таблицу comment:

CREATE TABLE [dbo].[comment] (
  [id] [int] IDENTITY (1, 1) NOT NULL ,
  [name] [varchar] (255) COLLATE Cyrillic_General_CI_AS NULL ,
  [city] [varchar] (255) COLLATE Cyrillic_General_CI_AS NULL ,
  [profession] [varchar] (255) COLLATE Cyrillic_General_CI_AS NULL ,
  [email] [varchar] (255) COLLATE Cyrillic_General_CI_AS NULL ,
  [msg] [varchar] (2000) COLLATE Cyrillic_General_CI_AS NULL ,
  [add_date] [datetime] NOT NULL
) ON [PRIMARY]
GO

Предложения о сотрудничестве

В таблице cooper, структура которой описана в табл. 9-3, хранятся записи с предложениями о сотрудничестве.

Таблица 9-3. Таблица cooper

Поле

Тип данных

Описание

id

int

Уникальный идентификатор записи

phone

varchar(255)

Телефон посетителя

msg

varchar(2000)

Сообщение, оставленное посетителем

add_date

datetime

Дата и время добавления записи

Эта таблица создается следующим сценарием SQL:

CREATE TABLE [dbo].[cooper] (
  [id] [int] IDENTITY (1, 1) NOT NULL ,
  [phone] [varchar] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [msg] [varchar] (2000) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [add_date] [datetime] NOT NULL
) ON [PRIMARY]
GO

Участники симпозиума

Информация о зарегистрированных участниках симпозиума хранится в таблице members, структура которой описана в табл. 9-4.

Таблица 9-4. Таблица members

Поле

Тип данных

Описание

id

int

Уникальный идентификатор записи

phone

varchar(255)

Телефон посетителя

msg

varchar(2000)

Сообщение, оставленное посетителем

add_date

datetime

Дата и время добавления записи

Вот сценарий SQL для создания таблицы members:

CREATE TABLE [dbo].[members] (
  [id] [int] IDENTITY (1, 1) NOT NULL ,
  [name] [varchar] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [city] [varchar] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [company] [varchar] (255) COLLATE Cyrillic_General_CI_AS NOT NULL
) ON [PRIMARY]
GO

Запись на госпитализацию

Информация о посетителях, записавшихся на госпитализацию, хранится в таблице record. Структура этой таблицы описана в табл. 9-4.

Таблица 9-4. Таблица record

Поле

Тип данных

Описание

id

int

Уникальный идентификатор записи

name

varchar(255)

Фамилия, имя и отчество посетителя

phone

varchar(255)

Телефон посетителя

email

varchar(255)

Адрес электронной почты посетителя

msg

varchar(2000)

Сообщение, оставленное посетителем

add_date

datetime

Дата и время добавления записи

Ниже мы привели сценарий SQL для создания таблицы record:

CREATE TABLE [dbo].[record] (
  [id] [int] IDENTITY (1, 1) NOT NULL ,
  [name] [varchar] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [phone] [varchar] (255) COLLATE Cyrillic_General_CI_AS NULL ,
  [email] [varchar] (255) COLLATE Cyrillic_General_CI_AS NULL ,
  [msg] [varchar] (2000) COLLATE Cyrillic_General_CI_AS NULL ,
  [add_date] [datetime] NOT NULL
) ON [PRIMARY]
GO

Доклады и докладчики

Информация о докладах и докладчиках, выступивших на симпозиуме, хранится в таблице reporters. Структура этой таблицы описана в табл. 9-5.

Таблица 9-5. Таблица reporters

Поле

Тип данных

Описание

id

int

Уникальный идентификатор записи

name

varchar(255)

Фамилия, имя и отчество посетителя

phone

varchar(255)

Телефон посетителя

email

varchar(255)

Адрес электронной почты посетителя

msg

varchar(2000)

Сообщение, оставленное посетителем

add_date

datetime

Дата и время добавления записи

Ниже приведен сценарий SQL для создания таблицы reporters:

CREATE TABLE [dbo].[reporters] (
  [id] [int] IDENTITY (1, 1) NOT NULL ,
  [conference_day] [varchar] (50) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [report_time] [varchar] (50) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [name] [varchar] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [all_names] [varchar] (255) COLLATE Cyrillic_General_CI_AS NOT NULL ,
  [title] [varchar] (2000) COLLATE Cyrillic_General_CI_AS NOT NULL
) ON [PRIMARY]
GO

Разделы Web-узла симпозиума

Web-узел симпозиума был создан нами для освещения материалов симпозиума по просьбе отделения сердечно-сосудистой хирургии (http://www.angio.ru) центра эндохирургии и литотрипсии ЦЭЛТ (http://www.celt.ru).

Помимо ссылок на Web-узлы ЦЭЛТ и отделения сердечно-сосудистой хирургии, на главной странице Web-узла симпозиума представлена следующая информация:

·         ангиограммы планируемых и выполненных операций;

·         список участников симпозиума;

·         список докладов участников симпозиума;

·         электронные версии докладов;

·         программа симпозиума;

·         бланки направлений на госпитализацию;

·         контактная и другая информация.

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

При этом участники симпозиума могли заранее ознакомиться с ангиограммами и кардиограммами планируемых операций (рис. 9-2), опубликованными на Web-узле http://forum.angio.ru. После проведения операций на Web-узле размещались ангиограммы сделанных операций.

Ангиограмма

Для тех, кто не знает, что такое ангиограмма, приведем следующую цитату, взятую из раздела «Энциклопедия для пациентов»  Web-узла  http://www.angio.ru:

«Ангиопластика — оперативное вмешательство, которое позволяет восстановить проходимость закупоренных или суженных жизненно важных кровеносных сосудов без открытой хирургической операции, без общего наркоза. Ангиопластика производится после ангиографического исследования специальным катетером, снабженным баллоном. Когда баллон находится в зоне закупоренного или суженного участка сосуда, врач раздувает баллон, расширяя артерию, и восстанавливает кровоток через эту зону. Ангиопластика проходит под рентген-контролем с помощью рентгеноконтрастного вещества».

Видеозапись операции, сделанная с рентгеновского аппарата, и называется ангиограммой.

Рис. 9-2. Ангиограммы планируемых операций

Щелкнув соответствующую ссылку, можно было просмотреть ангиорамму в окне приложения Windows Media Player (рис. 9-3).

Рис. 9-3. Просмотр ангиограммы пациента

Участники симпозиума, а также пользователи Интернета могли просмотреть и кардиограммы пациентов (рис. 9-4).

Рис. 9-4. Кардиограмма пациента

Далее мы расскажем о некоторых, наиболее интересных программных решениях, использованных нами при создании разделов Web-узла симпозиума http://forum.angio.ru.

Бланк направления на госпитализацию

В перерыве между докладами участники симпозиума могли подойти к компьютерам, подключенным к Интернету, и «побродить» по страницам Web-узла конференции. Один из разделов этого узла предоставлял возможность распечатать бланк направления на госпитализацию (рис. 9-5).

Рис. 9-5. Бланк направления на госпитализацию

Обратите внимание, что в верхней части бланка расположены кнопки Распечатать бланк и Закрыть окно. Если щелкнуть первую из этих кнопок, на экране появится стандартное окно Печать (Print), при помощи которого можно распечатать содержимое бланка. Вторая кнопка позволяет закрыть окно.

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

Фреймы бланка

Для того чтобы бланк распечатывался без кнопок Распечатать бланк и Закрыть окно, на странице бланка мы использовали фреймы. Исходный текст файла описания фреймов приведен в листинге 9-1.

Листинг 9-1 Вы найдете в файле chap09\forum.angio.ru\root\blanks\index.html на прилагаемом к книге компакт-диске.

В этом файле мы определили два фрейма, расположенных горизонтально:

<frameset FRAMEBORDER="1" rows="60,*">
  <frame SCROLLING="no" NAME="push" SRC="print.html" MARGINHEIGHT="1">
  <frame SCROLLING="auto" NAME="mainpage" SRC="blank.html">
<noframes>
  <body BGCOLOR="#FFFFFF">
  </body>
  </noframes>
</frameset>

Фрейм с кнопками с именем push находится в файле print.html (листинг 9-2), а фрейм с бланком направления на госпитализацию с именем  mainpage — в файле blank.html (листинг 9‑3).

Листинг 9-2 Вы найдете в файле chap09\forum.angio.ru\root\blanks\print.html на прилагаемом к книге компакт-диске.

Содержимое файла blank.html не представляет для нас особого интереса — там находится собственно бланк направления. Что же касается файла print.html, то он содержит сценарии JavaScript, с помощью которых и выполняется печать бланка.

Листинг 9-3 Вы найдете в файле chap09\forum.angio.ru\root\blanks\blank.html на прилагаемом к книге компакт-диске.

Сценарий печати бланка

Для того чтобы понять, как работает сценарий печати бланка, Вам нужно изучить язык сценариев JavaScript. Мы описали этот язык и привели многочисленные примеры сценариев в своей книге [1], посвященной созданию Web-приложений.

Функция loadPage, выполняющая печать бланка, определена в заголовке документа print.html следующим образом:

<head>
<title>Конференция - Бланк напрваления на госпитализацию</title>
<meta name="keywords" content="сердечно-сосудистая и интервенционная радиология">
<link rel="stylesheet" href="../style.css">
  <SCRIPT LANGUAGE="JavaScript">
  <!--
  function loadPage(szNewURL)
  {
    parent.mainpage.window.location.href=szNewURL;
    parent.mainpage.print();
  }
  // -->
  </SCRIPT>
</head>

Вначале эта функция загружает в нижний фрейм mainpage документ HTML, адрес которого передается ей в качестве параметра, а затем распечатывает его при помощи функции print.

В теле документа print.html определены кнопки Распечатать бланк и Закрыть окно.

Первая из этих кнопок определена следующим образом:

<A HREF="javascript:loadPage('blank.html');">
<img src="../images/blanks/print.gif" width="55" height="31" border="0"></a></td>
<td class="subtitle">
Распечатать бланк</td>

Если щелкнуть эту кнопку, будет вызвана функция loadPage, причем в качестве параметра мы передаем ей имя файла blank.html с бланком направления на госпитализацию. Функция загрузит бланк в нижний фрейм окна и распечатает его.

Щелчок кнопки Закрыть окно приведет к вызову функции window.close для родительского окна фрейма:

<A href="javascript:parent.window.close();" target="_blank">
<img src="../images/blanks/close.gif" width="55" height="31" border="0"></a></td>
<td class="subtitle">
Закрыть окно</td>

В результате окно, показанное на рис. 9-5, исчезнет с экрана.

Страница пожеланий и предложений

Для тех участников симпозиума, кто хотел бы оставить свое пожелание или предложение организаторам симпозиума, была создана специальная страница (рис. 9-6).

Рис. 9-6. Пожелания и предложения можно оставить здесь

Заполнив поля формы, расположенные на этой странице, нужно щелкнуть кнопку Отправить письмо. В результате сообщение будет отправлено в ЦЭЛТ по электронной почте. Вдобавок это сообщение будет записано в базу данных, созданной специально для Web-узла симпозиума.

Форма отправки сообщения

Исходный текст документа HTML с формой, предназначенной для отправки сообщения и показанной на рис. 9-6, Вы найдете в листинге 9-4.

Листинг 9-4 Вы найдете в файле chap09\forum.angio.ru\root\emailus\index.html на прилагаемом к книге компакт-диске.

Как видно из этого исходного текста, данные формы отправляются программе CGI с именем comment.pl:

<form action="/cgiprg/comment.pl" method="post">
<table width="100%" border="0" cellspacing="0" cellpadding="1" align="center" bgcolor="#66DE7F"><tr><td>
<table width="100%" border="0" cellspacing="0" cellpadding="4" align="center" bgColor="#F4F4F4">
<tr valign="top">
<td align="right" class="str">Ф.И.О.:</td><td><input type="text" name="NAME" size="25" maxlength="30"></td>
</tr>
<tr valign="top">
<td align="right" class="str">Где Вы живете:</td><td><input type="text" name="CITY" size="25" maxlength="30"></td>
</tr>
<tr valign="top">
<td align="right" class="str">Ваша профессия:</td><td><input type="work" name="PROFESSION" size="25" maxlength="30"></td>
</tr>
<tr valign="top">
<td align="right" class="str">Ваш e-mail адрес:</td><td><input type="work" name="EMAIL" size="25" maxlength="30"></td>
</tr>
<tr valign="top">
<td align="right" class="str">Ваше сообщение:</td><td><textarea cols="25" rows="4" name="MSG" type="" maxlength="30"></textarea></td>
</tr>
<tr valign="top">
<td colspan="2" align="center">  <table border="0" cellspacing="2" cellpadding="2"><tr>
  <td><input type="submit" value="Отправить письмо"></td>
  <td><input type="Reset" value="Очистить"></td>
  </tr></table>
</td></tr></table>
</td></tr></table>
</form>

Все поля формы, (кроме поля сообщения) — однострочные текстовые, созданные с помощью тега <INPUT>. Поле сообщения представляет собой многострочное поле <TEXTAREA>.

Программа comment.pl

Исходный текст программы CGI с именем comment.pl представлен в листинге 9-5. Заметим, что эта программа вызывает некоторые функции из пакета trudogolik.pl. Исходный текст версии этого файла, созданного для Web-узла симпозиума, представлен в листинге 9-6.

Листинг 9-5 Вы найдете в файле chap09\forum.angio.ru\cgi\comment.pl на прилагаемом к книге компакт-диске.

Итак, займемся программой comment.pl.

Получив управление, программа comment.pl извлекает данные из полей формы, преобразуя их в формат HTML при помощи уже знакомой Вам функции Trudogolik::ASCII_TO_HTML пакета trudogolik.pl:

my $name=Trudogolik::ASCII_TO_HTML(param('NAME'));
my $city=Trudogolik::ASCII_TO_HTML(param('CITY'));
my $profession=Trudogolik::ASCII_TO_HTML(param('PROFESSION'));
my $email=Trudogolik::ASCII_TO_HTML(param('EMAIL'));
my $msg=Trudogolik::ASCII_TO_HTML(param('MSG'));

Для того чтобы сообщение было информативным, программа проверяет, заполнил ли посетитель все необходимые поля формы:

if($name eq '' or $city eq '' or $profession eq '' or $email eq '' or $msg eq '')
{
  $template = HTML::Template->new(filename => 'template/ru/member_error.html');
}

В том случае, если поля Ф.И.О., Где Вы живете, Ваша профессия, Ваш e-mail адрес или Ваше сообщение (рис. 9-6) пусты, программа выводит страницу с сообщением об ошибке, используя для этого шаблон template/ru/member_error.html.

Если же все необходимые поля формы заполнены, программа записывает сообщение в таблицу comment базы данных Web-узла симпозиума:

$dbh = Trudogolik::DB_OPEN();
$sql="INSERT comment (name, city, profession, email, msg) VALUES (?, ?, ?, ?, ?)";
$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
Trudogolik::DB_SQL_BIND($sth, 1, $name, SQL_VARCHAR);
Trudogolik::DB_SQL_BIND($sth, 2, $city, SQL_VARCHAR);
Trudogolik::DB_SQL_BIND($sth, 3, $profession, SQL_VARCHAR);
Trudogolik::DB_SQL_BIND($sth, 4, $email, SQL_VARCHAR);
Trudogolik::DB_SQL_BIND($sth, 5, $msg, SQL_VARCHAR);
Trudogolik::DB_SQL_EXECUTE($sth);
Trudogolik::DB_CLOSE($dbh);

Здесь мы применили параметрический оператор SQL и известные Вам функции работы с базой данных посредством интерфейса DBI, определенные в пакете trudogolik.ru.

Записав сообщение в базу данных и закрыв соединение с ней, программа отправляет это же сообщение по электронной почте:

my $emsg="Почтовый робот сервера forum.angio.ru\n".
  "-----------------------------------------------\n".
  "Пожелания и предложения:"."\n\n".
  "Имя: ".$name."\n".
  "Город: ".$city."\n".
  "Профессия: ".$profession."\n".
  "E-Mail: ".$email."\n".
  "\n".$msg;

my $rc=send_mail('call@angio.ru', 'WebRobot@angio.ru',
  Trudogolik::win2koi('Пожелания и предложения'),
  Trudogolik::win2koi($emsg));
. . .
$template = HTML::Template->new(filename => 'template/ru/member_thank.html');

print "Content-Type: text/html\n";
print "Charset: windows-1251\n\n";
print $template->output;

Для отправки почты мы использовали здесь функцию send_mail, знакомую Вам по нашим предыдущим проектам, описанным в этой книге.

Листинг 9-6 Вы найдете в файле chap09\forum.angio.ru\cgi\trudogolik.pl на прилагаемом к книге компакт-диске.

Поиск участников симпозиума

По мере регистрации в базе данных симпозиума появлялись данные о новых участниках. Эти данные записывались в базу данных при помощи специального Web-приложения, которое мы рассмотрим позже в разделе «Администрирование Web-узла симпозиума» этой главы.

Текущий список участников можно было просмотреть на странице Зарегистрированные участники (рис. 9-7).

Рис. 9-7. Поиск участников симпозиума

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

На рис. 9-8 мы показали результат поиска московских участников симпозиума.

Рис. 9-8. Просмотр результатов поиска

Форма поиска участников

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

Исходный текст шаблона приведен в листинге 9-7.

Листинг 9-7 Вы найдете в файле chap09\forum.angio.ru\cgi\Template\ru\member_search.html на прилагаемом к книге компакт-диске.

Шаблон содержит форму, запускающую программу member_search_do.pl:

<form action="\cgiprg\member_search_do.pl" method="post">
. . .
</form>

Внутри этой формы мы определили несколько элементов управления и шаблонов.

Для ввода фамилии, имени и отчества участника используется простое текстовое поле:

<tr valign="top">
<td align="right" class="str">
Ф. И. О.</td>
<td><input type="text" name="FIO" size="30" maxlength="80">
</td></tr>

Для ввода названия города мы применили комбинацию текстового поля и списка, заполняемого при помощи циклического шаблона CITY_LIST:

<tr valign="top">
<td align="right" class="str">
Город</td>
<td>
введите с клавиатуры
<br><input type="text" name="CITY1" size="30" maxlength="80">
<br>
или выберите из списка
<br><select name="CITY">
 <option value="0">-
любой -
<TMPL_LOOP NAME="CITY_LIST">
<option value="<TMPL_VAR NAME=CITY_NAME>"><TMPL_VAR NAME=CITY_NAME>
</TMPL_LOOP>
</select>
</td></tr>

Верхняя строка списка со значением параметра VALUE, равным нулю, позволяет исключить название города из условий поиска.

Ввод места работы выполняется аналогично:

<tr valign="top">
<td align="right" class="str">
Место работы</td>
<td>
<select name="COMPANY">
 <option value="0">-
любое -
<TMPL_LOOP NAME="COMPANY_LIST">
<option value="<TMPL_VAR NAME=COMPANY_NAME>"><TMPL_VAR NAME=COMPANY_NAME>
</TMPL_LOOP>
</select>
</td></tr>

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

Для того чтобы получить полный список участников, мы вызываем программу member_search_do.pl с параметрами CITY и COPANY, равными нулю:

<span class="str">или же Вы можете перейти к просмотру полного списка участников</span>
<br><br>
<img src="../images/li-arrow.gif" width="34" height="21" border="0" alt="" align="top">&nbsp; <a href="\cgiprg\member_search_do.pl?CITY=0&COMPANY=0">Полный список участников симпозиума.</a>

Программа заполнения формы поиска

Чтобы создать страницу поиска, показанную на рис. 9-7, мы использовали только что описанный шаблон member_search.html (листинг 9-7), а также программу member_search.pl (листинг 9-8).

Рассмотрим исходный текст этой программы.

Листинг 9-8 Вы найдете в файле chap09\forum.angio.ru\cgi\member_search.pl на прилагаемом к книге компакт-диске.

Задачей программы member_search.pl является заполнение циклических шаблонов для списков названия городов и компаний. Информация для заполнения берется из базы данных Web-узла симпозиума.

Получив управление, программа записывает в переменную $template путь к шаблону страницы поиска и открывает соединение с базой данных:

my $template = HTML::Template->new(filename => 'template/ru/member_search.html');
$dbh = Trudogolik::DB_OPEN();

На следующем этапе программа выбирает все уникальные называния городов из таблицы members, хранящей сведения об участниках симпозиума:

$sql="select distinct city from members";
$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
Trudogolik::DB_SQL_EXECUTE($sth);

@::loop = ();
while(($m_city)= Trudogolik::DB_SQL_FETCHROW_ARRAY($sth))
{
  my %row = (CITY_NAME => $m_city);
  push(@::loop, \%row);
}
$template->param(CITY_LIST => \@::loop);

Выбранные данные используются для заполнения циклического шаблона CITY_LIST.

На втором этапе выполняется заполнение списка названий компаний, в которых работают участники симпозиума:

$sql="select distinct company from members";
$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
Trudogolik::DB_SQL_EXECUTE($sth);

@::loop = ();
while(($m_company)= Trudogolik::DB_SQL_FETCHROW_ARRAY($sth))
{
  my %row = (COMPANY_NAME => $m_company);
  push(@::loop, \%row);
}
$template->param(COMPANY_LIST => \@::loop);

Список формируется при помощи циклического шаблона COMPANY_LIST.

Перед завершением работы программа закрывает соединение с базой данных и отображает шаблон:

Trudogolik::DB_CLOSE($dbh);
print "Content-Type: text/html\n";
print "Pragma: no-cache\n";
print "Cache-Control: no-cache\n";
print "Expires: Thu Jan  1 01:01:01 1970\n";
print "Charset: windows-1251\n\n";
print $template->output;

Заметим, что при отображении мы отключаем кэширование страницы результатов поиска.

Программа выполнения поиска

Когда пользователь щелкает кнопку Найти участника в форме, показанной на рис. 9-7, управление передается программе поиска member_search_do.pl (листинг 9-9).

Листинг 9-9 Вы найдете в файле chap09\forum.angio.ru\cgi\member_search_do.pl на прилагаемом к книге компакт-диске.

Получив управление, программа member_search_do.pl открывает соединение с базой данных и получает содержимое полей ввода формы поиска:

$dbh = Trudogolik::DB_OPEN();
my $fio=Trudogolik::ASCII_TO_HTML(param('FIO'));
my $city=Trudogolik::ASCII_TO_HTML(param('CITY'));
my $city1=Trudogolik::ASCII_TO_HTML(param('CITY1'));
my $company=Trudogolik::ASCII_TO_HTML(param('COMPANY'));

Перед дальнейшей обработкой вся введенная информация преобразуется в кодировку HTML с помощью функции Trudogolik::ASCII_TO_HTML.

Если посетитель ввел название города в текстовом поле, а не выбрал его из списка, мы добавляем в конец введенной строки символ %, чтобы команда LIKE могла искать по первым символам названия города:

if($city1 ne '')
{
  $city = $city1."%";
}

Далее формируется строка параметризованной команды SQL:

$sql="select name, city, company from members where name LIKE ?";

Чтобы настроить эту строку в зависимости от того, какие поля формы поиска были заполнены, мы используем четыре флажка:

my $fio_used=0;
my $city_used=0;
my $city_used1=0;
my $company_used=0;

Если посетитель указал название города, мы добавляем соответствующее условие в строку запроса SQL:

if($city ne "0")
{
  $sql = $sql." AND city LIKE ?";
  $city_used=1;
}

Аналогично для названия компании:

if($company ne "0")
{
  $sql = $sql." AND company=?";
  $company_used=1;
}

Так как результат поиска должен быть отсортирован по фамилии участника, мы делаем последнее добавление в строку запроса и подготавливаем эту строку к выполнению при помощи функции Trudogolik::DB_SQL_PREPARE:

$sql = $sql." order by name";
$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);

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

Trudogolik::DB_SQL_BIND($sth, 1, $fio."%", SQL_VARCHAR);

if($city ne "0")
{
  Trudogolik::DB_SQL_BIND($sth, 2, $city, SQL_VARCHAR);
}
if($company ne "0")
{
  if($city_used == 0)
  {
    Trudogolik::DB_SQL_BIND($sth, 2, $company, SQL_VARCHAR);
  }
  else
  {
    Trudogolik::DB_SQL_BIND($sth, 3, $company, SQL_VARCHAR);
  }
}

Завершив привязку, программа выполняет команду:

Trudogolik::DB_SQL_EXECUTE($sth);

Теперь нужно заполнить циклический шаблон registered.html (листинг 9-10) для страницы с результатами запроса :

my $template = HTML::Template->new(filename => 'template/ru/registered.html');

$i=0;
@::loop = ();
while(($m_name, $m_city, $m_company)= Trudogolik::DB_SQL_FETCHROW_ARRAY($sth))
{
  if($i % 2)
  {
    $row_class = 'd';
  }
  else
  {
    $row_class = 'l';
  }
  my %row = (NAME => $m_name, CITY => $m_city, COMPANY => $m_company, ROW_CLASS => $row_class);
  push(@::loop, \%row); $i++;
}
$template->param(MEMBER_LIST => \@::loop);

Если был запрошен полный список участников, мы заполняем условный шаблон FULL_LIST:

if($city_used==0 and $company_used==0)
{
  $template->param(FULL_LIST => 1);
}

На последнем шаге программа закрывает соединение с базой данных и отображает страницу с результатами поиска:

Trudogolik::DB_CLOSE($dbh);
print "Content-Type: text/html\n";
print "Pragma: no-cache\n";
print "Cache-Control: no-cache\n";
print "Expires: Thu Jan  1 01:01:01 1970\n";
print "Charset: windows-1251\n\n";
print $template->output;

Шаблон страницы с результатами поиска

Исходный текст шаблона страницы с результатами поиска registered.html представлен в листинге 9-10.

Листинг 9-10 Вы найдете в файле chap09\forum.angio.ru\cgi\Template\ru\registered.html на прилагаемом к книге компакт-диске.

Название списка формируется с помощью условного шаблона FULL_LIST:

<td width="100%" align="center" bgcolor="#F4F4F4"><font class="topline">Зарегистрированные участники симпозиума<TMPL_IF NAME="FULL_LIST"> - Полный список</TMPL_IF></font></td>

Если посетитель просматривает полный список, название списка дополняется строкой Полный список.

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

<img src="../images/li-up.gif" width="34" height="21" border="0" alt="" align="top">&nbsp;
<a href="/cgiprg/member_search.pl">Вернуться на страницу поиска.</a>

Список найденной информации об участниках симпозиума формируется с помощью таблицы и циклического шаблона MEMBER_LIST:

<table width="100%" border="0" cellspacing="0" cellpadding="1" align="center" bgcolor="#66DE7F"><tr><td>
<table width="100%" border="0" cellspacing="0" cellpadding="6" align="center">
<TR class="h"><TD align="left">Фамилия, имя, отчество</TD><TD align="left">Город</TD><TD align="left">Место работы</TD></TR>
<TMPL_LOOP NAME="MEMBER_LIST">
<tr class="<TMPL_VAR NAME=ROW_CLASS>"><td><TMPL_VAR NAME=NAME></td><td><TMPL_VAR NAME=CITY></td><td><TMPL_VAR NAME=COMPANY></td></tr>
</TMPL_LOOP>
</table>

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

Поиск докладов

Большинство участников симпозиума предоставило файлы своих докладов. Все эти доклады были опубликованы на Web-узле симпозиума в разделе Электронные версии докладов на симпозиуме (рис. 9-9).

Рис. 9-9. Электронные версии докладов, сделанных на симпозиуме

Чтобы найти доклады того или иного докладчика, мы предусмотрели специальную форму поиска, размещенную в подразделе Поиск докладчиков раздела Программа симпозиума (рис. 9‑10).

Рис. 9-10. Поиск докладов по фамилии докладчика

Чтобы получить список докладов того или иного участника симпозиума,  достаточно ввести фамилию участника в поле Фамилия (полностью или частично). Результат поиска по одной из фамилий показан на рис. 9-11.

Рис. 9-11. Список найденных докладов

Форма поиска докладов

Исходя из требований дизайна, страница поиска докладчиков создана с применением фреймов. Описание фреймов находится в файле index5.html (листинг 9-11).

Листинг 9-11 Вы найдете в файле chap09\forum.angio.ru\root\schedule\index5.html на прилагаемом к книге компакт-диске.

Для нас представляет интерес нижний фрейм с именем main, определенный в файле search.html:

<frameset  cols="190,*" marginwidth="0" marginheight="0" frameborder="0"  border="0">
  <frame name="left" src="left.html" marginwidth="0" marginheight="0" scrolling="no" frameborder="0"  border="0">
  <frameset  rows="70,*">
     <frame name="top" src="top5.html" marginwidth="0" marginheight="0" scrolling="no" frameborder="0"  border="0">
     <frame name="main" src="search.html" marginwidth="0" marginheight="0" scrolling="yes" frameborder="0"  border="0">
  </frameset>
</frameset>

Исходный текст файла search.html представлен в листинге 9-12.

Листинг 9-12 Вы найдете в файле chap09\forum.angio.ru\root\schedule\search.html на прилагаемом к книге компакт-диске.

Здесь находится определение несложной формы с полем вода Фамилия:

<form action="/cgiprg/reporter_search_do.pl" method="post">
<table width="100%" border="0" cellspacing="0" cellpadding="1" align="center" bgcolor="#66DE7F"><tr><td>
<table width="100%" border="0" cellspacing="0" cellpadding="4" align="center" bgColor="#F4F4F4">
<tr valign="top">
<td align="right" class="str">Фамилия:</td><td><input type="text" name="NAME" size="25" maxlength="30"></td>
</tr>
<tr valign="top"><td>&nbsp;</td>
<td align="left"> 
<table border="0" cellspacing="2" cellpadding="2"><tr>
  <td><input type="submit" value="Найти доклады"></td>
  <td>&nbsp;</td>
  </tr>
</table>
</td></tr></table>
</td></tr></table>
</form>

Когда пользователь щелкает кнопку Найти доклады, форма запускает программу поиска докладов reporter_search_do.pl.

Программа поиска докладов

Исходный текст программы поиска докладов reporter_search_do.pl представлен в листинге 9-13.

Листинг 9-13 Вы найдете в файле chap09\forum.angio.ru\cgi\reporter_search_do.pl на прилагаемом к книге компакт-диске.

Получив управление, программа открывает соединение с базой данных, а также инициализирует переменную $template ссылкой на шаблон страницы результатов поиска search_reporters_result.html:

$dbh = Trudogolik::DB_OPEN();
my $template = HTML::Template->new(filename => 'template/ru/search_reporters_result.html');

Фамилия, введенная посетителем, преобразуется в формат HTML при помощи функции Trudogolik::ASCII_TO_HTML:

my $name=Trudogolik::ASCII_TO_HTML(param('NAME'));

Далее мы удаляем начальные и конечные пробелы из введенной строки фамилии, а затем добавляем к началу и концу строки символы %:

$name =~ s/^s+//;
$name =~ s/\s+$//;
$name = "%".$name."%";

Таким способом мы обеспечиваем поиск докладов с помощью команды LIKE по фамилиям, введенным не полностью.

Далее программа формирует параметризованную команду поиска, готовит ее и привязывает параметр, а затем запускает на выполнение:

$sql="select conference_day, report_time, all_names, title from reporters where name LIKE ? order by conference_day, report_time ";

$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);

Trudogolik::DB_SQL_BIND($sth, 1, $name, SQL_VARCHAR);
Trudogolik::DB_SQL_EXECUTE($sth);

Результат выполнения команды используется для заполнения циклического шаблона REPORT_LIST, при помощи которого формируется страница с результатами запросов:

@::loop = ();
while((my $m_conference_day, my $m_report_time, my $m_all_names, my $m_title)= Trudogolik::DB_SQL_FETCHROW_ARRAY($sth))
{
  my %row = (DAY => $m_conference_day, TIME => $m_report_time, NAME => $m_all_names, TITLE => $m_title);
  push(@::loop, \%row);
}
$template->param(REPORT_LIST => \@::loop);

Затем программа закрывает соединение с базой данных и отображает результаты поиска, показанные на рис. 9-11:

Trudogolik::DB_CLOSE($dbh);
print "Content-Type: text/html\n";
print "Charset: windows-1251\n\n";
print $template->output;

Администрирование Web-узла симпозиума

В этом разделе мы расскажем о том, как устроен Web-узел, созданный для администрирования узлов симпозиума http://forum.angio.ru и узла отделения сердечно-сосудистой хирургии ЦЭЛТ http://www.angio.ru.

Узел администрирования (рис. 9-12) позволяет решать следующие задачи:

·         загрузка списка участников симпозиума в базу данных;

·         обновление списка докладов;

·         загрузка файлов ангиограмм и других произвольных файлов на сервер с помощью браузера;

·         просмотр сообщений посетителей в базе данных симпозиума;

·         просмотр записей на консультацию и предложений о сотрудничестве, оставленных посетителями Web-узлов http://forum.angio.ru и http://www.angio.ru

Рассмотрим программные решения, использованные при создании наиболее интересных разделов административного Web-узла симпозиума.

Рис. 9-12. Администрирование Web-узлом конференции и отделения ангиологии

Загрузка списка участников симпозиума

Участники симпозиума регистрировались при помощи программы, созданной с использованием СУБД Microsoft Access. Несколько раз в день список участников экспортировался из этой СУБД в виде текстовой таблицы, записи которой были разделены символом точка с запятой.

Вот несколько строк из этой таблицы:

"Абалмасов";"Константин";"Георгиевич";"Москва";
"Скок";"Леонид";"Миланович";"Саратов";"Гор. клин. б-ца №1"
"Акчурин";"Ренат";"Сулейманович";"Москва";"РКНПК МЗ РФ"
"Алексеев";"Петр";"Алексеевич";"Смоленск";"Гор. клин. б-ца №6"
"Алекян";"Баграт";"Гегамович";"Москва";"НЦ ССХ им. А.Н. Бакулева"
"Амброзайтис";"Рамунас";"Казиович";"Вильнюс";"Онкологический центр Литвы"
"Амосов";"Иван";"Степанович";"Всеволжск";
. . .

Щелкнув на главной странице узла администрирования ссылку Загрузить файл списка участников на сервер (рис. 9-12), администратора загружал в свой браузер страницу загрузки, показанную на рис. 9-13.

Рис. 9-13. Загрузка нового списка участников симпозиума

На этой странице вначале нужно щелкнуть кнопку Browse и выбрать исходный текстовый файл, экспортированный из Microsoft Access, расположенный на локальном диске  рабочей станции администратора. Далее для того чтобы загрузить файл в каталог Web-сервера, необходимо воспользоваться кнопкой Загрузить.

Через некоторое время результаты загрузки файла отобразятся в окне браузера (рис. 9‑14).

Рис. 9-14. Список участников конференции загружен на сервер

В нижней части страницы будет показано содержимое загруженного файла.

Прием файлов через документы HTML

Использованная здесь технология загрузки файлов посетителей на сервер Web (часто называемая технологией File Upload) основана на экспериментальном протоколе, описанном в документе RFC1867 (если Вы не знакомы с описаниями RFC, сходите на сервер http://www.cis.ohio-state.edu/htbin/rfc). Документ RFC1867 называется «Form-based file Upload in HTML», что можно перевести как «прием файлов через документы HTML».

В этом документе помимо всего прочего описывается применение строки FILE в качестве возможного значения атрибута TYPE тега <INPUT>, создающего элементы управления в формах. Этот элемент управления состоит из однострочного текстового поля и расположенной справа от него кнопки с надписью Browse, предназначенной для выбора файла на локальном диске.

Кроме того, в атрибуте ENCTYPE тега <FORM> для передачи файлов предлагается указывать тип данных multipart/form-data, что отличается от привычного формата application/x-www-form-urlencoded. Формат данных multipart/form-data позволяет передавать данные типа MIME и, в частности, произвольные двоичные данные, которыми в общем случае являются все файлы. Что же касается формата application/x-www-form-urlencoded, используемого по умолчанию, то он пригоден только для передачи текстовых данных.

Чтобы сохранить содержимое файла в базе данных, щелкните ссылку Запустите… (рис. 9-14). Результат можно будет увидеть на странице, показанной на рис. 9-15.

Рис. 9-15. Список участников сохранен в базе данных

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

Форма для загрузки файла

В листинге 9-14 мы привели исходный текст формы, показанной на рис. 9-13.

Листинг 9-14 Вы найдете в файле chap09\admin.angio\root\upload.html на прилагаемом к книге компакт-диске.

Обратите внимание, что параметр ENCTYPE формы задан как multipart/form-data. Это необходимо для правильной загрузки файлов по протоколу RFC1867:

<form enctype="multipart/form-data" method="POST" action="/cgiprg/uploader.pl">
<p>1.
Выберите текстовый файл списка участников конференции:<br><br>
<input type="file" size="40" name="UploadedFile">
<P>2.
Для загрузки файла щелкните кнопку <b>Загрузить</b>:<br><br>
<input type="submit" name="SeeUploadedFile" value="
Загрузить">
</p>
</form>

В форме мы определили поле UploadedFile, предназначенное для выбора загружаемого файла. Если щелкнуть кнопку Загрузить, будет запущена программа загрузки файла  uploader.pl, к описанию которой мы и переходим.

Программа загрузки файла списка участников симпозиума

В своей книге [1], посвященной разработке Web-приложений, мы привели исходные тексты и подробное описание приложения ISAPI, позволяющего загружать файлы на Web-сервер Microsoft IIS. Это приложение было использовано нами при создании Интернет-магазина http://www.itbook.ru, Web-узла издательства компьютерной литературы «Русская Редакция», а также в некоторых других проектах, созданных с применением технологий компании Microsoft.

Что же касается Linux и других Unix-подобных операционных систем, то для решения подобной задачи существует несколько готовых программ CGI, написанных на языке Perl.

При создании Web-узла симпозиума мы решили воспользоваться одной такой, наиболее удачной, на наш взгляд,  программой загрузки файлов. Ее разработал программист Simon Tneoh Chee-Boon (tneohcb@tneoh.zoneit.com или tneohcb@pc.jaring.my). В соответствии с лицензионным соглашением Вы можете бесплатно загрузить ее из Интернета по адресу http://www.tneoh.zoneit.com/cgi/upload, а затем (также бесплатно) использовать в своих проектах.

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

В листинге 9-15 мы привели исходный текст программы загрузки файла.

Листинг 9-15 Вы найдете в файле chap09\admin.angio\cgi\uploader.pl на прилагаемом к книге компакт-диске.

В начальном фрагменте программы необходимо указать пакет CGI_LIB.pl:

#!/usr/local/bin/perl
use HTML::Template;
require 'CGI_LIB.pl';

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

binmode(STDIN);
binmode(STDOUT);
binmode(STDERR);

Далее в программе вызывается функция Parse_Multi, определенная в пакете CGI_LIB.pl:

&Parse_Multi;

Она загружает все данные от полей формы, в том числе и файл. После загрузки функция создает хэш %CGI, элементы которого содержат данные из полей формы, а также данные загруженного файла.

В элементе $CGI{'UploadedFile'}->{'Content-Type'} находится тип MIME принятого файла. В нашем случае загружается текстовый файл, поэтому тип MIME должен быть text/plain. Если это не так, наша программа выводит страницу с сообщением об ошибке:

if($CGI{'UploadedFile'}->{'Content-Type'} eq 'text/plain')
{
  . . .
}
else
{
  $template = HTML::Template->new(filename => 'template/ru/file_upload_error.htm');
  print "Content-Type: text/html\n";
  print "Charset: windows-1251\n\n";
  print $template->output;
}

В том случае, когда тип файла правильный, программа открывает выходной файл TMP на диске Web-сервера, копирует в него содержимое принятого файла, а затем закрывает выходной файл:

open(TMP, "> D:/admin.angio/root/upload/members.txt");
binmode(TMP);
print TMP $CGI{'UploadedFile'}->{'Contents'};
close(TMP);

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

На следующем шаге наша программа выводит в окно браузера содержимое файла, формируя страницу HTML с помощью шаблона  file_upload_ok.htm (листинг 9-16):

$template = HTML::Template->new(filename => 'template/ru/file_upload_ok.htm');

print "Content-Type: text/html\n";
print "Charset: windows-1251\n\n";
 
my $file= $CGI{'UploadedFile'}->{'Contents'};
 
$file =~ s/\n/<br>/g;
 
$template->param(UPLOADED_FILE => $file);
  print $template->output;

При выводе символ перехода на новую строку в данных принятого файла заменяется тегом <br>.

Листинг 9-16 Вы найдете в файле chap09\admin.angio\cgi\Template\ru\ file_upload_ok.htm на прилагаемом к книге компакт-диске.

Что же касается шаблона file_upload_ok.htm, то в нем предусмотрена ссылка на программу update.pl, предназначенную для сохранения содержимого принятого файла в базе данных Web-узла симпозиума:

<p>2. <A href="/cgiprg/update.pl">Запустите</A> обновление списка участников в базе данных.</p>

Программа сохранения списка участников в базе данных

Рассмотрим теперь только что упомянутую программу сохранения содержимого принятого файла update.pl (листинг 9-17).

Листинг 9-17 Вы найдете в файле chap09\admin.angio\cgi\update.pl на прилагаемом к книге компакт-диске.

Вот заголовок этой программы:

#!/usr/bin/perl -w
use CGI qw(:all);
use HTML::Template;
use Text::ParseWords;
use DBI qw(:sql_types);
use strict;
require 'trudogolik.pl';

Обратите внимание, что здесь мы подключили модуль Text::ParseWords. Этот модуль окажет нам существенную помощь в разборе содержимого текстового файла списка участников, поля которого разделены символом точка с запятой.

Получив управление, программа update.pl прежде всего открывает базу данных и удаляет старый список участников из таблицы members:

$dbh = Trudogolik::DB_OPEN();
Trudogolik::DB_SQL_DO($dbh, 'DELETE FROM members');

Далее программа открывает входной файл, загруженный администратором через браузер с использованием протокола RFC1867:

open (MEMBERS_FILE, "D:/admin.angio/root/upload/members.txt") || die;

Обратите внимание, что здесь мы указали абсолютный путь к файлу. При перемещении этот путь необходимо отредактировать.

Открытый файл читается и обрабатывается в цикле:

while(<MEMBERS_FILE>)
{
  @words = &quotewords(';', 0, $_);
  $name = $words[0].' '.$words[1].' '.$words[2]; 
  chomp $name;
  $city = $words[3];
  chomp $city;
  $company = $words[4];
  chomp $company;
 
  if($city eq '')
  {
    $city = '-';
  }
  if($company eq '')
  {
    $company = '-';
  }

  $sql="INSERT members (name, city, company) VALUES (?, ?, ?)";
  $sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
  Trudogolik::DB_SQL_BIND($sth, 1, Trudogolik::ASCII_TO_HTML($name), SQL_VARCHAR);
  Trudogolik::DB_SQL_BIND($sth, 2, Trudogolik::ASCII_TO_HTML($city), SQL_VARCHAR);
  Trudogolik::DB_SQL_BIND($sth, 3, Trudogolik::ASCII_TO_HTML($company), SQL_VARCHAR);
  Trudogolik::DB_SQL_EXECUTE($sth);
}

С помощью функции quotewords программа разбирает каждую строку файла «на составные части», выделяя имя, название города и компании. Эта информация затем вставляется в соответствующие поля таблицы members.

После завершения обработки входного файла программа его закрывает:

close (MEMBERS_FILE);

Далее для контроля результата загрузки программа выдает запрос к базе данных, выбирая все записи из таблицы members:

$sql="select id, name, city, company from members order by name";
$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
Trudogolik::DB_SQL_EXECUTE($sth);

Эта информация затем отображается в табличном виде с применением циклического шаблона MEMBER_LIST:

my $template = HTML::Template->new(filename => 'template/ru/upload_ok.htm');

my $i=1;
@::loop = ();
while((my $m_id, my $m_name, my $m_city, my $m_company)= Trudogolik::DB_SQL_FETCHROW_ARRAY($sth))
{
  my %row = (ID => $i, NAME => $m_name, CITY => $m_city, COMPANY => $m_company);
  push(@::loop, \%row); $i++;
}
$template->param(MEMBER_LIST => \@::loop);

Перед завершением работы программа закрывает соединение с базой данных и выводит заполненный шаблон в окно браузера:

Trudogolik::DB_CLOSE($dbh);

#print header (-charset=>'windows-1251'); 
print "Content-Type: text/html\n";
print "Pragma: no-cache\n";
print "Cache-Control: no-cache\n";
print "Expires: Thu Jan  1 01:01:01 1970\n";
print "Charset: windows-1251\n\n";
print $template->output;

Исходный текст шаблона, использованного нами при формировании страницы с результатом обновления списка участников (рис. 9-15), представлен в листинге 9-18.

Листинг 9-18 Вы найдете в файле chap09\admin.angio\cgi\Template\ru\upload_ok.htm на прилагаемом к книге компакт-диске.

Здесь мы применили циклический шаблон MEMBER_LIST:

<h2>Загрузка базы данных выполнена успешно</h2>
<font class="norm"><a href="/index.html">[В начало]</a>&nbsp;&nbsp;<a href="\upload.html">[Выбор файла для загрузки]</a></font>
<hr>
<p>Список участников конференции, загруженный в базу данных:</p>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<tr align=left><th width=20>N</th><th width=250>Имя, фамилия, отчество</th><th width=100>Город</th><th>Компания</th></tr>
<TMPL_LOOP NAME="MEMBER_LIST">
<tr align=left>
<td width=20><TMPL_VAR NAME=ID></td>
<td width=250><TMPL_VAR NAME=NAME></td>
<td width=100><TMPL_VAR NAME=CITY></td>
<td><TMPL_VAR NAME=COMPANY></td></tr>
</TMPL_LOOP>
</table>

Загрузка списка докладов

Список докладов, так же как и список участников, экспортировался для загрузки на Web-узел симпозиума в виде текстового файла:

"1";"10:40-11:00";"Шевченко";"Шевченко Ю.Л.";"Кардиохирургия, вчера, сегодня, завтра"
"1";"11:00-11:20";"Кавтеладзе";"Кавтеладзе З.А. (Москва)";"Стентирование вчера и сегодня. А что завтра? Временные стенты?!"
"1";"11:20-11:40";"Галанкина";"Галанкина И.Е. (Москва)";"Морфологические проявления баллонной ангиопластики и стентирования"
"1";"12:20-12:40";"Лякишев";"Лякишев А.А. (Москва)";"Медикаментозное лечение ИБС, современное состояние вопроса"
"1";"12:40-13:00";"Радованович";"Радованович Н. (Швейцария)";"Современное состояние хирургического лечения ИБС"
"1";"13:00-13:20";"Рейфарт";"Рейфарт Н. (Германия)";"Современное состояние коронарной ангиопластики"
"1";"13:20-13:40";"Бабунашвили";"Бабунашвили А.М. (Москва)";"20 лет поиска: медикаменты, ангиопластика или хирургия?"

Как видите, поля этого файла разделены символом точка с запятой. В первом поле указан номер дня симпозиума, когда был сделан доклад (1, 2 или 3), далее дет время доклада, фамилия основного докладчика, фамилии всех содокладчиков и, наконец, название доклада.

С помощью формы, показанной на рис. 9-10, посетители могли искать доклады по фамилии основного докладчика и просматривать результаты поиска на странице, показанной на рис. 9-11.

Щелкнув ссылку Обновление списка докладов в базе данных (рис. 9-12), администратор мог загрузить в базу данных текущий список докладов. Результаты загрузки отображались на отдельной странице административного Web-узла (рис. 9-16).

Рис. 9-16. Загружен новый файл списка докладов

Исходный текст программы загрузки списка представлен в листинге 9-19.

Листинг 9-19 Вы найдете в файле chap09\admin.angio\cgi\update_reporters.pl на прилагаемом к книге компакт-диске.

Помимо обычных модулей, в заголовке программы мы загружаем модуль Text::ParseWords, необходимый для разбора исходного файла:

#!/usr/bin/perl -w
use CGI qw(:all);
use HTML::Template;
use Text::ParseWords;
use DBI qw(:sql_types);
use strict;
require 'trudogolik.pl';

Получив управление, программа открывает базу данных и удаляет прежнее содержимое таблицы reporters, содержащей сведения о докладах:

$dbh = Trudogolik::DB_OPEN();
Trudogolik::DB_SQL_DO($dbh, 'DELETE FROM reporters');

Далее программа открывает исходный текстовый файл reporters.txt, содержащий информацию о докладах, разбирает его и загружает в таблицу reporters:

open (MEMBERS_FILE, "D:/admin.angio/root/upload/reporters.txt") || die;
while(<MEMBERS_FILE>)
{
  @words = &quotewords(';', 0, $_);
  $conference_day = $words[0];
  chomp $conference_day;
  $report_time = $words[1];
  chomp $report_time;
  $name = $words[2];
  chomp $name;
  $all_names = $words[3];
  chomp $all_names;
  $title = $words[4];
  chomp $title;
 
  $sql="INSERT reporters (conference_day, report_time, name, all_names, title) VALUES (?, ?, ?, ?, ?)";
  $sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
  Trudogolik::DB_SQL_BIND($sth, 1, Trudogolik::ASCII_TO_HTML($conference_day), SQL_VARCHAR);
  Trudogolik::DB_SQL_BIND($sth, 2, Trudogolik::ASCII_TO_HTML($report_time), SQL_VARCHAR);
  Trudogolik::DB_SQL_BIND($sth, 3, Trudogolik::ASCII_TO_HTML($name), SQL_VARCHAR);
  Trudogolik::DB_SQL_BIND($sth, 4, Trudogolik::ASCII_TO_HTML($all_names), SQL_VARCHAR);
  Trudogolik::DB_SQL_BIND($sth, 5, Trudogolik::ASCII_TO_HTML($title), SQL_VARCHAR);
  Trudogolik::DB_SQL_EXECUTE($sth);
}
close (MEMBERS_FILE);

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

Далее программа извлекает только что загруженную информацию из базы данных и отображает ее для контроля:

$sql="select conference_day, report_time, name, all_names, title from reporters order by conference_day, report_time";
$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
Trudogolik::DB_SQL_EXECUTE($sth);

my $template = HTML::Template->new(filename => 'template/ru/upload_reporters_ok.htm');

my $i=1;
@::loop = ();
while((my $m_conference_day, my $m_report_time, my $m_name, my $m_all_names, my $m_title)= Trudogolik::DB_SQL_FETCHROW_ARRAY($sth))
{
  my %row = (DAY => $m_conference_day, TIME => $m_report_time, NAME => $m_all_names, TITLE => $m_title);
  push(@::loop, \%row); $i++;
}
$template->param(REPORTER_LIST => \@::loop);

Перед завершением работы программа закрывает соединения с базой данных и выводит заполненный шаблон:

Trudogolik::DB_CLOSE($dbh);

print "Content-Type: text/html\n";
print "Pragma: no-cache\n";
print "Cache-Control: no-cache\n";
print "Expires: Thu Jan  1 01:01:01 1970\n";
print "Charset: windows-1251\n\n";
print $template->output;

В листинге 9-20 мы привели исходный текст шаблона, применяемого для создания страницы с результатами загрузки списка докладов, показанной на рис. 9-16.

 

Листинг 9-20 Вы найдете в файле chap09\admin.angio\cgi\Template\ru\upload_reporters_ok.htm на прилагаемом к книге компакт-диске.

В нем мы определили циклический шаблон REPORTER_LIST:

<h2>Файл списка докладов</h2>
<font class="norm"><a href="/index.html">[В начало]</a></font>
<hr>
<p>Просмотрите содержимое файла.</p>
<font class="norm">
<TMPL_LOOP NAME="REPORTER_LIST">
<TMPL_VAR NAME=DAY>, <TMPL_VAR NAME=TIME>, <TMPL_VAR NAME=NAME>, "<TMPL_VAR NAME=TITLE>"
<br><br>
</TMPL_LOOP>
</font>

Загрузка файлов ангиограмм и других файлов

 

Чтобы решить задачу загрузки любых файлов произвольного формата через браузер в специально выделенный для этой цели каталог Web-сервера, мы создали в административном узле раздел Загрузить файл ангиограммы.

Щелкнув соответствующую ссылку на главной странице административного узла (рис. 9‑12), можно отобразить в окне браузера страницу загрузки файлов, показанную на рис. 9‑17.

Рис. 9-17. Загрузка файла в формате Microsoft Power Point

Эта страница очень похожа на страницу загрузки списка участников симпозиума (рис. 9‑13), однако в ней предусмотрено дополнительное поле описания файла Введите описание файла. Загрузив файл, программа автоматически создает еще один текстовый файл с описанием содержимого файла, взятого из этого поля.

После загрузки файла в окне браузера появляется страница с результатами загрузки (рис. 9-18).

Рис. 9-18. Ангиограмма успешно загружена

На ней отображается исходное имя файла, имя, под которым этот файл сохранен на сервере, тип и размер файла, а также текстовое описание файла.

Форма загрузки файла представлена в листинге 9-21.

Листинг 9-21 Вы найдете в файле chap09\admin.angio\cgi\Template\root\ upload_angio.html  на прилагаемом к книге компакт-диске.

Поле описания файла определено здесь при помощи тега <TEXTAREA>:

<H2>Загрузка файлов ангиограмм</H2>
<font class="norm"><a href="index.html">[В начало]</a></font>
<hr>
<form enctype="multipart/form-data" method="POST" action="/cgiprg/uploader_angio.pl">
<p>1.
Выберите файл ангиограммы:<br><br>
<input type="file" size="40" name="UploadedFile">
<p>2. Введите описание файла:<br><br>
<textarea cols="30" rows="8" name="FDESCR"></textarea>
<P>3. Для загрузки файла щелкните кнопку <b>Загрузить</b>:<br><br>
<input type="submit" name="SeeUploadedFile" value="Загрузить"></p>
</form>

Исходный текст программы загрузки uploader_angio.pl, запускаемой этой формой, Вы найдете в листинге 9-22.

Листинг 9-22 Вы найдете в файле chap09\admin.angio\cgi\uploader_angio.pl на прилагаемом к книге компакт-диске.

Он напоминает исходный текст описанной ранее программы uploader.pl (листинг 9-15), поэтому мы рассмотрим только отличия.

Получив управление, программа uploader_angio.pl загружает содержимое полей формы и файл, а затем пытается определить тип файла:

binmode(STDIN);
binmode(STDOUT);
binmode(STDERR);
&Parse_Multi;

my $filename_ext;
my $content_type = $CGI{'UploadedFile'}->{'Content-Type'};

if($content_type    eq 'text/plain') { $filename_ext = 'txt'; }
elsif($content_type eq 'text/html') { $filename_ext = 'html'; }
elsif($content_type eq 'image/gif') { $filename_ext = 'gif'; }
elsif($content_type eq 'image/pjpeg') { $filename_ext = 'jpg'; }
elsif($content_type eq 'application/vnd.ms-powerpoint') { $filename_ext = 'ppt'; }
elsif($content_type eq 'video/avi') { $filename_ext = 'avi'; }
elsif($content_type eq 'video/mpeg') { $filename_ext = 'mpg'; }
elsif($content_type eq 'application/msword') { $filename_ext = 'doc'; }
elsif($content_type eq 'application/vnd.ms-excel') { $filename_ext = 'xls'; }
elsif($content_type eq 'application/octet-stream') { $filename_ext = 'bin'; }
elsif($content_type eq 'application/x-zip-compressed') { $filename_ext = 'zip'; }
else { $filename_ext = 'unknown_type'; }

Если это ей удается, в переменную $filename_ext записывается расширение имени файла, которое необходимо использовать при сохранении принятого файла, а если нет — используется расширение unknown_type.

Далее программа определяет длину файла:

my $file_size = length($CGI{'UploadedFile'}->{'Contents'});

В том случае, если она не превышает заданного нами значения, программа открывает выходной файл и копирует в него принятые данные:

if($file_size < 6000000)
{

my ($sec, $min, $hour, $mday, $mon, $year);
($sec, $min, $hour, $mday, $mon, $year) = (localtime)[0, 1, 2, 3,4,5]; $year += 1900;

my $filename = 'f.'.$mday."-".$mon."-".$year.".".$hour."-".$min."-".$sec.".".$filename_ext;

open(TMP, "> D:/admin.angio/root/upload_angio/".$filename);
binmode(TMP);
print TMP $CGI{'UploadedFile'}->{'Contents'};
close(TMP);

open(TMP, "> D:/admin.angio/root/upload_angio/".$filename.".info.txt");
binmode(TMP);
print TMP $CGI{'FDESCR'};
close(TMP);

Кроме того, создается файл с описанием принятого файла, имеющий расширение имени info.txt.

Далее программа заполняет шаблон выходной страницы (рис. 9-18), записывая в него информацию о принятом файле:

$template = HTML::Template->new(filename => 'template/ru/file_upload_angio_ok.htm');
print "Content-Type: text/html\n";
print "Charset: windows-1251\n\n";
 
$template->param(CONTENT_TYPE => $CGI{'UploadedFile'}->{'Content-Type'} );
$template->param(FILE_NAME => $CGI{'UploadedFile'}->{'filename'} );
$template->param(DST_FILE_NAME => $filename );
$template->param(FILE_SIZE => $file_size );
$template->param(FILE_DESCR => Trudogolik::ASCII_TO_HTML($CGI{'FDESCR'}) );
print $template->output;

Исходный текст используемого для этой страницы шаблона Вы найдете в листинге 9-23.

Листинг 9-23 Вы найдете в файле chap09\admin.angio\cgi\Template\ru\file_upload_angio_ok.htm на прилагаемом к книге компакт-диске.

Здесь мы используем обычные шаблоны с именами FILE_NAME, DST_FILE_NAME, CONTENT_TYPE, FILE_SIZE и FILE_DESCR:

<h2>Файл ангиограммы загружен</h2>
<font class="norm"><a href="/index.html">[В начало]</a>&nbsp;&nbsp;<a href="\upload_angio.html">[Выбор файла ангиограммы для загрузки]</a></font>
<hr>
<p>Информация о загруженном файле</p>
<table border="1" cellspacing="0" cellpadding="5">
<tr><td><b>Исходное имя файла</b></td>
<td><TMPL_VAR NAME=FILE_NAME></td></tr>
<tr><td><b>Имя файла на сервере</b></td>
<td><TMPL_VAR NAME=DST_FILE_NAME></td></tr>
<tr><td><b>Тип файла</b></td>
<td><TMPL_VAR NAME=CONTENT_TYPE></td></tr>
<tr><td><b>Размер файла</b></td>
<td><TMPL_VAR NAME=FILE_SIZE> байт</td></tr>
<tr><td><b>Описание файла</b></td>
<td><TMPL_VAR NAME=FILE_DESCR>&nbsp;</td></tr>
</table>

Просмотр сообщений посетителей Web-узла симпозиума

Последний раздел административного Web-узла симпозиума, который мы рассмотрим в этой главе, предназначен для просмотра сообщений посетителей симпозиума, оставленных ими в форме, показанной на рис. 9-6.

Страница просмотра сообщений показана на рис. 9-19. Ее можно увидеть, если на главной странице административного Web-узла (рси. 9-12) щелкнуть ссылку Просмотреть сообщения посетителей.

Рис. 9-19. Просмотр сообщений посетителей

Исходный текст программы просмотра сообщений представлен в листинге 9-24.

Листинг 9-24 Вы найдете в файле chap09\admin.angio\cgi\view_comment.pl на прилагаемом к книге компакт-диске.

Открыв соединение с базой данных, программа выбирает все записи из таблицы comment, хранящей сообщения посетителей:

$dbh = Trudogolik::DB_OPEN();

$sql="select add_date, name, city, profession, email, msg from comment order by add_date desc";
$sth = Trudogolik::DB_SQL_PREPARE($dbh, $sql);
Trudogolik::DB_SQL_EXECUTE($sth);

Далее эти сообщения отображаются при помощи циклического шаблона MESSAGE_LIST:

my $template = HTML::Template->new(filename => 'template/ru/comments.htm');

my $i=1;
@::loop = ();
while((my $m_add_date, my $m_name, my $m_city, my $m_profession, my $m_email, my $m_msg)= Trudogolik::DB_SQL_FETCHROW_ARRAY($sth))
{
  my %row = (ADD_DATE => $m_add_date, NAME => $m_name, CITY => $m_city, PROFESSION => $m_profession, EMAIL => $m_email, MSG => $m_msg);
  push(@::loop, \%row); $i++;
}

$template->param(MESSAGE_LIST => \@::loop);

Заполнив шаблон, программа закрывает соединение с базой данных и выводит шаблон в окно браузера:

Trudogolik::DB_CLOSE($dbh);

#print header (-charset=>'windows-1251'); 
print "Content-Type: text/html\n";
print "Pragma: no-cache\n";
print "Cache-Control: no-cache\n";
print "Expires: Thu Jan  1 01:01:01 1970\n";
print "Charset: windows-1251\n\n";
print $template->output;

Исходный текст шаблона представлен в листинге 9-25.

Листинг 9-25 Вы найдете в файле chap09\admin.angio\cgi\Template\ru\comments.htm на прилагаемом к книге компакт-диске.

В нем находится определение циклического шаблона MESSAGE_LIST:

<h2>Сообщения посетителей конференции</h2>
<font class="norm"><a href="/index.html">[В начало]</a></font>
<hr>
<TMPL_LOOP NAME="MESSAGE_LIST">
<font class="norm"><b><TMPL_VAR NAME=NAME></b> (<TMPL_VAR NAME=CITY>), <TMPL_VAR NAME=PROFESSION>, <TMPL_VAR NAME=EMAIL><br>
<i><TMPL_VAR NAME=ADD_DATE></i><br>
<TMPL_VAR NAME=MSG></font>
<hr>
</TMPL_LOOP>

С применением этого шаблона формируется страница сообщений, показанная на рис. 9‑19.

[Назад] [Содержание] [Дальше]