Гостевая
Форум
Разделы
Главная страница
Js скрипты
Php скрипты
Html шаблоны
Книги по Web дизайну
Статьи


Главная страница статей --> Хитрости при программировании php, заметки по базам данных

Взаимодействие нескольких форм

Источник: realcoding.net

Введение

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

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

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

Существует несколько стратегий, позволяющих осуществить сохранение контекста. Ими являются:

* Скрытые поля. Используя скрытые поля, можно включать невидимую информацию в форму, посылаемую следующему CGI-сценарию.
* Включения на стороне CGI. Этот механизм позволяет вставлять в документ специальные тэги, незаметно для пользователя передающие CGI переменные.
* Cookies. Данный механизм позволяет сохранять определенную информацию на стороне клиента.

Существует также четвертый способ - создать специальный cookie-сервер, с которым будет взаимодействовать каждый CGI-сценарий. Данный способ мы рассмотрим в следующий раз.

Скрытые поля формы


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

Приведу пример определения двух скрытых полей формы:

<form action=/cgi-bin/sendmail.pl method=post>
...
<
input type=hidden name=mail_to
value=andrey@novikov.com>
<
input type=hidden name=subject
value=Test letter>
...
</
form>

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

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

<form action=/cgi-bin/firststep.pl method=post>
Введите Ваше имя: <input type=text name=realname>
<
br>
Введите Ваш адрес: <input type=text name=email>
<
br>
<
input type=submit name=Send
value=Следующий шаг>
<
input type=reset name=Reset value=Очистить>
</
form>

При посылке этой формы на сервер соответствующий сценарий динамически генерирует следующую форму, содержащую скрытые поля:

<form action=/cgi-bin/secondstep.pl method=post>
<
input type=hidden name=realname
value=Андрей Новиков>
<
input type=hidden name=email
value=andrey@novikov.com>
Город проживания: <input type=text name=city>
<
br>
<
input type=submit name=Send
value=Следующий шаг>
<
input type=reset name=Reset value=Очистить>
</
form>

И так до самого конца. Достоинством такого подхода является отсутствие необходимости временных файлов и "волшебных cookies". С другой стороны недостатком такого подхода авляется снижение производительности при обработке форм с большим количеством полей.

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

#!/usr/local/bin/perl
print Content-type: text/htmlnn;

read(STDIN, $buffer, $ENV{CONTENT_LENGTH});
@
pairs = split(/&/, $buffer);
foreach
$pair (@pairs) {
local($name, $value) = split(/=/, $pair);
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
$value =~ s/<!--(.n)*-->//g;
$FORM_DATA{$name} = $value;
}

print
<form name=newtext action=newtext.pl
method=post>
,n;
foreach
$key (keys %FORM_DATA) {
$value = $FORM_DATA{$key};
print
<input type=hidden name=$name
value=
$value>n;
}
print <<
END;
Можете добавить мысль:<br>
<
textarea name=text rows=5 cols=50></textarea><br>
<
input type=submit name=post value=Добавить>
<
input type=reset name=escape value=Очистить>
</
form>
END

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

<form action=/cgi-bin/shopping.pl/firstspep.html
method=post>
Введите Ваше имя: <input type=text name=realname>
<
br>
Введите Ваш адрес: <input type=text name=email>
<
br>
<
input type=submit name=Send
value=Следующий шаг>
<
input type=reset name=Reset value=Очистить>
</
form>

Обратите внимание на то, что в этом примере скрипту передается параметр PATH_INFO, содержащий имя следующего отображаемого документа с формой. Этот документ должен содержать форму, в которую сценарием shopping.pl будут добавлены все скрытые поля. Вот примерный текст такого сценария:

#!/usr/local/bin/perl
print Content-type: text/htmlnn;

read(STDIN, $buffer, $ENV{CONTENT_LENGTH});
@
pairs = split(/&/, $buffer);
foreach
$pair (@pairs) {
local($name, $value) = split(/=/, $pair);
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
$value =~ s/<!--(.n)*-->//g;
$FORM_DATA{$name} = $value;
}

$form_file = $ENV{PATH_INFO};
$full_path = /usr/local/etc/httpd/htdocs .
$form_file;

open(FILE, < . $full_path);
while (<
FILE>) {
if (/<
s*forms*.*>/i) {
print;
foreach
$key (keys %FORM_DATA) {
$value = $FORM_DATA{$key};
print
<input type=hidden name=$name
     value=
$value>n;
}
} else {
print;
}
}
close(FILE);

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

Включения на стороне CGI


Технология включений не стороне CGI (назовем ее CSI) подразумевает включение специальных кусков кода в HTML документы, очень похожих на SSI. Этот код обрабатывает специальный CGI-сценарий, который заменяет их на конкретные данные, позволяющие сохранять контекст.

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

<html>
<
head><title></title></head>
<
body>
<
ul>
<
li><a href=/cgi-bin/takeit.cgi?cookie=
<!--#insert var=
COOKIE-->&film_id=1>
Ну, погоди!</a>
<
li><a href=/cgi-bin/takeit.cgi?cookie=
<!--#insert var=
COOKIE-->&film_id=2>
Колобок</a></ul>
<
a href=/cgi-bin/csi.pl/next.html?cookie=
<!--#insert var=
COOKIE-->>Далее</a>
<
form action=/cgi-bin/buyit.cgi?cookie=
<!--#insert var=
COOKIE--> method=post>
Ваше имя: <input type=text
name=name><br>
<
input type=submit value=Купить>
</
form>
</
body></html>

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

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

http://www.your.sever.ru/cgi-bin/csi.pl/
film_cathalog.html

Сам сценарий обработки CSI выглядит примерно так:

#!/usr/local/bin/perl
print Content-type: text/htmlnn;

read(STDIN, $buffer, $ENV{CONTENT_LENGTH});
@
pairs = split(/&/, $buffer);
foreach
$pair (@pairs) {
local($name, $value) = split(/=/, $pair);
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
$value =~ s/<!--(.n)*-->//g;
$FORM_DATA{$name} = $value;
}

$cookie = $FORM_DATA{cookie};
$cookie = join(_, $ENV{REMOTE_HOST}, time)
if (!
$cookie);
$cookie =~ s/(W)/sprintf(%%%x, ord($1))/eg;

$form_file = $ENV{PATH_INFO};
$full_path = /usr/local/etc/httpd/htdocs .
$form_file;

open(FILE, < . $full_path);
while (<
FILE>) {
while ( (
$command, $argument, $parameter) =
(/<!--
s*#s*(w+)s+(w+)s*=s*?
         
(w+)?s*-->/io) ) {
if ($command eq
insert) {
if ($argument eq
var) {
if ($parameter eq
COOKIE) {
s//$cookie/;
} elsif ($parameter eq
DATE_TIME) {
local ($time) = &get_date_time();
s//$time/;
} else {
s///;
}
}
}
print;
}
close(FILE);

В моем случае поддерживаются только команды insert с аргументом var и двумя параметрами: COOKIE и DATE_TIME. Но Вы можете ввести любые необходимые Вам команды, аргументы и параметры. Только следите при этом за отсутствием совпадений с SSI.

Cookies


Все предыдущие примеры ничего не требовали от клиента. Механизм использования cookies, основывается на изобретенной Netscape технологии хранения данных на стороне клиента.

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

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

Программа, желающая сохранить cookie у клиента должна начинаться примерно так:

#!/usr/local/bin/perl

read(STDIN, $buffer, $ENV{CONTENT_LENGTH});
local($key, $value) = split(/=/, $buffer);
print
Content-type: text/htmln;
print
Set-Cookie: $key=$value; expires=Sat,
26-Aug-95 15:45:30 GMT;
path=/; domain=webclub.runn
;
...
exit(
0);

Можно в одном заголовке указывать несколько строк установки cookie:

Set-Cookie: book_id=123156; path=/shop;
domain=webclub.ru
Set
-Cookie: city_id=434; path=/shop;
domain=webclub.ru

Сохраненные данные сценарий может прочитать в переменной окружения HTTP_COOKIE. Код программы выглядит примерно так:

@cookie_pairs = split(/;s/, $ENV{HTTP_COOKIE});
foreach
$pair (@cookie_pairs) {
(
$key, $pair) = split(/=/, $pair);
$key =~ tr/+/ /;
$key =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(C,
hex($1))/eg;
if (
defined($FORM_DATA{$key}) {
# Вам надо решить, что делать если
    
есть cookie и данные
# формы с одним и тем же ключом.
} else {
$FORM_DATA{$key} = $value;
}
}

Одной из проблем при использовании данной технологии для создания крупных систем является наличие ограничений по размеру одного cookie - 4Kb, количеству cookies от одного сорвера - 20, и общему количеству cookies для каждого пользователя - 300. Вы всегда должны помнить о них при создании крупных систем.

Заключение


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

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



Похожие статьи:
- 21 ошибка программиста PHP
- Современные технологии продвижения сайтов
- Изменение внешнего вида счетчика в CNStats
- Программная выписка счета в системе WebMoney
- Графический счетчик на Perl
- Работа с хэшами в Perl
- Создание wap-страниц (в формате *.wml)
- За что можно схлопотать бан от поисковых систем!
- Освоение Ajax: Использование XML в запросах и ответах
- Некоторые аспекты использования пользовательских функций в предложениях SQL.
- ADO и XML
- Динамические формы - проверка ввода на JavaScript
- SQL Server в вопросах и ответах


Оглавление | Обсудить на форуме | Главная страница сайта | Карта сайта |
[0.001]