parser

Простой механизм обратной связи

Misha v.3 [16 апреля 2004]

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

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

Весь механизм обратной связи будет находиться в одном файле /feedback.html который сначала будет показывать формочку, а в случае поста на него выполнять действия по отправке письма. Если у вас данный код будет находиться по иному пути, не забудьте поправить action в <form />

@main[]
<html>
<body>
^rem{ *** на какой адрес будет отправляться письмо *** }
$sTo[to@email.ru]
^rem{ *** от какого адреса будет отправляться письмо *** }
$sFrom[robot@$env:SERVER_NAME]

^if($form:action eq "done"){
	^rem{ *** сюда мы попадём после внешнего редиректа когда всё уже успешно отправилось *** }
	^rem{ *** тут пишем посетителю что-нить доброе за то, что он отправил нам пожелание *** }
	$bShowForm(0)
	<p>Спасибо, что отправили нам свое пожелание.</p>
}{
	^rem{ *** устанавливаем флаг, что надо показывать форму *** }
	$bShowForm(1)
}

^if(def $form:do){
	^rem{ *** если что-то пришло к нам в элементе 'do' - значит форма сабмитится *** }
	^if(^isOk[]){
		^rem{ *** если данные валидные, то пробуем отправить письмо *** }
		^try{
			^send[$sTo;$sFrom]
			^rem{ *** делаем _внешний_ редирект на себя, чтобы защититься от Reload *** }
			^rem{ *** правда от Back все равно таким образом не защититься *** }
			^rem{ *** для того, чтобы редирект был внешним не забываем начать адрес с http:// *** }
			^Lib:location[$request:uri^if(^request:uri.pos[?]>=0){&amp;}{?}action=done;$.bExternal(1)]
		}{
			^rem{ *** использовали try т.к. в отправке письма может возникнуть ошибка *** }
			^rem{ *** и тут мы окажемся, если эта ошибка таки возникла *** }

			^rem{ *** говорим парсеру, что с этой ошибкой мы разберёмся сами *** }
			$exception.handled(1)
			
			^rem{ *** ну и надо что-нить сообщить пользователю в связи с ошибкой *** }
			^rem{ *** конечно хорошо-бы ещё записать что-нить в лог файл про эту ошибку *** }
			<p>Сожалеем, но при отправке письма возникла неизвестная ошибка.</p>
		}

		^rem{ *** сбрасываем флаг, что нужно показывать форму *** }
		$bShowForm(0)
	}{
		^rem{ *** не заполнены какие-то поля формы. ругаемся. *** }
		^rem{ *** при этом не сбрасываем флаг что нужно показывать форму. *** }
		^rem{ *** т.е. после ругани у нас покажется форма *** }
		^rem{ *** при этому уже заполненные ранее пользователям данные не будут потеряны *** }
		<p>Не заполнены обязательные поля формы!</p>
	}
}
^rem{ *** показываем форму, если установлен соответствующий флаг *** }
^if($bShowForm){
	^rem{ *** если собираемся отправлять файлы то не забываем прописать указанный enctype!!! *** }
	<form
		method="post"
		action="/feedback.html"
		enctype="multipart/form-data"
	>
		^rem{ *** именно по этому элементу мы будем определять, постится форма или нет *** }
		^rem{ *** если вы хотите анализировать это по элементу 'action', то вашу форму невозможно... *** }
		^rem{ *** ...будет запостить с помощью нажатия клавиши enter или с помощью js события *** }
		<input type="hidden" name="do" value="do" />

		Ваше имя:<br />
		<input type="text" name="name" value="$form:name" /><br />
		E-mail:<br />
		<input type="text" name="email" value="$form:email" /><br />
		Ваш комментарий:<br />
		<textarea name="comment">$form:comment</textarea><br />
		Дополнительный файл:<br />
		<input type="file" name="attach" /><br />

		<input type="submit" name="action" value="Отправить" />
	</form>
}
</body>
</html>
#end @main[]


# метод проверяет заполненность полей формы. если все хорошо - возвращает true
@isOk[]
$result(def $form:name &amp;&amp; def $form:comment)
#end @isOk[]


# метод отправки сообщения
@send[sTo;sFrom][dtNow]
$dtNow[^date::now[]]
^mail:send[
	$.to[$sTo]
	$.from[^if(^Lib:isEmail[$form:email]){$form:email}{$sFrom}]
	^rem{ *** кодировка, в которой отправляется письмо *** }
	$.charset[$response:charset]
	$.subject[Обратная связь с сайта http://$env:SERVER_NAME/]
	$.text[Пользователь: $form:name
^if(def $form:email){E-mail: $form:email^#0A}Комментарий:
$form:comment^#0A^#0AСообщение отправлено: ^dtNow.sql-string[]]
	^rem{ *** если посетитель приаттачил файл - отправляем и его *** }
	^if($form:attach is "file"){
		$.file[$form:attach]
	}
]
$result[]
#end @send[]


Данный код использует класс Lib.p, поэтому необходимо скачать и подключить его.

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