Форма обратной связи на сайте
Для тех, кому нужен просто скрипт обратной связи для своего сайта – инструкция по установке этого плагина отдельно от движка.
Даже если ваш сайт только информационный и вы не собираетесь создавать на его базе модную социальную сеть, обратная связь все равно должна быть. Читатели захотят связаться с вами, что-нибудь уточнить, предложить, в конце концов сообщить свое мнение о сайте. Не лишать же их этой возможности. Первое, что приходит в голову – разместить где-нибудь в подвале страницы свой E-mail и пускай связываются. Но можно гарантировать, что спамеры, обнаружив этот адрес, «свяжутся» с вами раньше и потом уже не отвяжутся. Да и отношение к электронной почте у пользователей меняется. Если раньше нормой было использование почтовых программ-агентов, то сейчас все больше пользуются веб-интерфейсом. И нам совсем нетрудно предоставить им этот интерфейс.
Нужно нам для этого немного – еще один плагин. Зарезервируем для него алиас feedback, вряд ли так будет называться что-то другое. Соответственно, по правилам подключения плагинов, которые действуют в этом движке, файл будет называться feedback.inc.php и расположен будет в директории /libs.
<?php // Шаблон для проверки формата E-mail $pat = '^([a-z0-9\._\-]+)@([a-z0-9\.\-]+)(\.[a-z]{2,})$'; // Шаблон для проверки имени (инверсный!) $txt_pat = "/[^0-9a-z '\.A-ZА-Яа-я--]/"; // Если массив POST не пустой, отправка состоялась if (!empty($_POST) && !isset($sent)) { // «Распаковываем» массив POST и отсекаем пробельные символы foreach ($_POST as $var=>$val) // ...но проверяем, не подсунули ли нам поле с адресом if ($var != 'tomail') $$var = trim($val); // Если подсунули – прекращаем работу скрипта else exit; // Статусное сообщение. Пока оно пустое... $state_msg=''; $msg_color='navy'; // Сверяем имя с шаблоном $fname = (isset($fname)? preg_replace($txt_pat, '', $fname) : ''); // Сверяем адрес E-mail с шаблоном $mail = ((isset($mail) && eregi($pat,$mail))? strtolower($mail) : ''); // Теперь проверяем заполнение всех полей if (empty($fname)) { // Если имя пустое... $state_msg='Введите имя.'; } elseif (empty($mail)) { // Если адрес пустой... $state_msg='Неверный формат (или не указан) E-mail'; } elseif (empty($comment)) { // Если сообщение пустое... $state_msg='Вы не ввели текст сообщения'; } else { // Если все поля заполнены верно... // Готовим сообщение об успешной отправке... $msg_color='red'; $state_msg='Ваше сообщение отправлено.<br> Нажмите <a href="'.$_SERVER['REQUEST_URI'].'">здесь</a>, если ваш браузер не поддерживает перенаправление.'; $user_ip=$_SERVER['REMOTE_ADDR']; // Готовим Subject письма... $subj='=?windows-1251?B?'. base64_encode('Запрос с '.$PROJ_NAME).'?='; // Готовим заголовки письма... $header='From: '.$mail."\n"; $header.='Content-Type: text/plain; charset="windows-1251"'."\n"; $header.="Content-Transfer-Encoding: 8bit\n"; // Собираем текст письма... $post_message='Обращается '.$fname."\n\n"; $post_message.='E-mail: '.$mail."\n"; $post_message.="Сообщение:\n"; $post_message.=$comment."\n\n"; // На всякий случай включаем IP-адрес отправителя... $post_message.='IP-адрес '.$user_ip."\nОтправлено ".date("d-m-Y H:i:s"); // ... и наконец, отправляем письмо. mail($tomail,$subj,$post_message,$header); // А переменная $sent – признак успешной отправки. $sent=1; } } else { // Если в массиве POST пусто, форма еще не передавалась // Готовим приглашение $msg_color='navy'; $state_msg='Заполните форму и отправьте сообщение.'; // Поля имени, адреса и текста в этом случае должны быть пустыми $fname=$mail=$comment=''; } // Если сообщение еще не отправлялось, выводим форму if (!isset($sent)) $outstr=' <form method=post action="'.$_SERVER['REQUEST_URI'].'"> <table width=85% border=0> <tr><td align=center colspan=2 style="color:'.$msg_color.'"> '.$state_msg.'</td></tr> <tr><td width=20% align=right>Ваше имя:</td> <td><input type=text name="fname" size=60 value="'.$fname.'"></td></tr> <tr><td align=right>E-mail:</td> <td><input type=text name="mail" size=60 value="'.$mail.'"></td></tr> <tr><td align=right valign=top>Ваше сообщение:</td> <td> <textarea name=comment wrap=virtual cols=62 rows=5>'.$comment.'</textarea> </td></tr> <tr><td> </td><td> <input type=submit name=subm value="Отправить"> </td></tr></table> </form> '; else { // А если сообщение уже отправлено... // Посылаем в заголовке редирект (303 Refresh) на этот же адрес // с задержкой на 3 секунды, чтобы пользователь увидел сообщение $ret_uri=$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; header("Refresh: 3; URL=http://".$ret_uri); // Выводим сообщение об отправке echo ("<br><br><font color=".$msg_color.">".$state_msg."</font>"); exit; } ?>
Соответственно, в файле конфигурации у нас появится еще одна строчка – с адресом E-mail, на который будут отправляться сообщения:
$tomail="yourmail@domain.ru";
Мне очень нравится такая логика обработки форм – она позволяет выполнить все действия, не вызывая никаких внешних скриптов, на всех этапах обработки формы мы остаемся в пределах одного и того же адреса страницы. Вначале проверяем, есть ли что-нибудь в массиве POST. Если есть, значит наш скрипт получил отправленные данные (то есть был запущен по POST-запросу как action формы). Проверяем на корректность POST-переменные, если они правильно заполнены, собираем и отсылаем письмо.
Небольшое, но важное дополнение. Уже после написания этого раздела скрипт был исправлен. Собирая этот плагин, я не выносил в файл конфигурации переменную $tomail – адрес, на который будут отсылаться сообщения. Ей присваивалось значение прямо перед отправкой письма. Выкладывая сюда скрипт, я исправил это, но не подумал о разборе массива POST. А ведь в процессе разбора определяются переменные и кто-то может подбросить в данные формы поле с названием tomail и таким образом передать через фидбэк письмо на произвольный адрес. Какая радость для спамеров, можно превратить сайт в средство рассылки! Теперь цикл разбора дополнен условием: если встречена POST-переменная с таким именем, скрипт немедленно завершает работу.
А далее у нас стоит второе условие: если письмо уже отослано, выводится сообщение об отправке и делается редирект на тот же адрес. А если письмо еще не отсылалось (страница загружена по GET-вызову или были ошибки в POST-переменных), будет выведена форма. Использован редирект с задержкой (Refresh, html-эквивалент заголовка HTTP с кодом статуса 303) – за время задержки посетитель успеет увидеть сообщение об отправке. Редирект на ту же страницу грузит форму GET-запросом «с чистого листа» и предотвращает повторную отсылку письма, если посетителю придет в голову обновить страницу (если бы не редирект, POST-данные в таком случае отправились бы на обработку повторно).
Кстати, если нужно, возврат на тот же URL после отправки формы можно использовать и без задержки, и без отправки каких-либо сообщений в браузер. Достаточно после обработки POST-формы сделать перенаправление на этот же URL, только код статуса должен быть обязательно 303. Этот вариант редиректа придуман специально для возвращения на POST-форму после ее обработки. Он всегда отдает страницу по GET, так что все поля формы будут в исходном состоянии, а все POST-переменные уничтожены. Обновление страницы с формой не вызовет повторной отправки.
Обратите внимание: шаблон для адреса E-mail сделан с учетом формата адреса, а шаблон для имени – инверсный, то есть буквально он означает «любые символы, кроме перечисленных». В нем перечислены только те символы, которые могут попасться в человеческом имени. При проверке preg_relpace() заменяет пустым значением все ненужные символы, которые соответствуют этому шаблону (то есть не входят в перечисленные).
Для адреса E_mail проверка двойная: если он не пустой и соответствует шаблону, то остается без изменений. Иначе он будет заменен пустым значением.
Остается последовательно проверить, не пусты ли переменные формы после этой сверки. Если обнаружена пустая, в подсказку (переменную $state_msg) помещаем сообщение об ошибке. Условие многоступенчатое, так что только его последняя альтернатива приводит к отправке письма, любая встреченная «пустышка» только заполнит подсказку сообщением об ошибке без отправки письма (подсказка выводится в верхней строке формы).