Быстрая CMS
Обратная связь Карта сайта
Главная Создание сайтов Практика Строим CMS Наивное О проекте Блог

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


Для тех, кому нужен просто скрипт обратной связи для своего сайта – инструкция по установке этого плагина отдельно от движка.
 

Даже если ваш сайт только информационный и вы не собираетесь создавать на его базе модную социальную сеть, обратная связь все равно должна быть. Читатели захотят связаться с вами, что-нибудь уточнить, предложить, в конце концов сообщить свое мнение о сайте. Не лишать же их этой возможности. Первое, что приходит в голову – разместить где-нибудь в подвале страницы свой 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) помещаем сообщение об ошибке. Условие многоступенчатое, так что только его последняя альтернатива приводит к отправке письма, любая встреченная «пустышка» только заполнит подсказку сообщением об ошибке без отправки письма (подсказка выводится в верхней строке формы).