Статья, в которой рассмотрим, как создать форму обратной связи для сайта, используя HTML, JavaScript (jQuery), популярный фронт-энд фреймворк Bootstrap, технологию AJAX и PHP. Форма будет работать без перезагрузки страницы. Переданные посетителем данные будут отправляться на почту (email).

Файловая структура формы обратной связи

Форма обратной связи и логика её работы осуществляется посредством файлов, расположенных в каталоге feedback на сервере.

Данная директория имеет следующую структуру:

feedback/
├── css/
│   └── bootstrap.min.css
├── js/
│   ├── jquery-3.1.0.min.js
│   └── bootstrap.min.js
├── fonts/
│    ├── glyphicons-halflings-regular.eot
│    ├── glyphicons-halflings-regular.svg
│    └── ...
├── phpmailer/
│    ├── PHPMailerAutoload.php
│    ├── class.phpmailer.php
│    └── ...
├── background.png
├── captcha.php
├── index.html
├── message.txt
├── oswald.ttf
├── process.php
└── script.js

Назначение файлов:

  • bootstrap.min.css, bootstrap.min.js и файлы шрифтов в директории fonts (платформа Twitter Bootstrap 3);
  • jquery-3.1.0.min.js (библиотека jQuery);
  • background.png (фон, на который будет накладываться шрифт при создании капчи);
  • captcha.php (php код, генерирующий капчу);
  • index.html (страница, содержащая html код формы обратной связи);
  • message.txt (текстовый файл, в который при необходимости можно записывать информацию с формы обратной связи);
  • oswald.ttf (шрифт, с помощью которого будем писать код капчи на изображении);
  • script.js (скрипт, обеспечивающий функционирование формы обратной связи в браузере);
  • файлы, расположенные в директории phpmailer (php библиотека для отправки писем);
  • process.php (php код, который будет обрабатывать данные формы на стороне сервера).

Описание формы обратной связи

По умолчанию контактная форма (feedback) доступна посетителю сайта на странице /feedback/index.html.

HTML форма обратной связи (feedback)
HTML форма обратной связи (feedback)

Она состоит 3 полей (имя, email, сообщение), капчи и кнопки "Отправить сообщение".

Дизайн формы feedback выполнен в стиле Twitter Bootstrap 3. Процесс создания такого оформления осуществляется посредством добавления CSS классов Bootstrap к необходимым HTML элементам формы.

HTML код формы обратной связи (index.html):

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>Bootstrap - AJAX форма обратной связи</title>
  <link rel="stylesheet" href="/feedback/css/bootstrap.min.css">
</head>
<body>

  <h1 class="h2 page-header text-center">Bootstrap - AJAX форма обратной связи</h1> 

  <div class="container">
    <div class="row">
      <div class="col-sm-6 col-sm-offset-3">
        <!-- Контейнер, содержащий форму обратной связи -->
        <div class="panel panel-info">
          <!-- Заголовок контейнера -->
          <div class="panel-heading">
            <h3 class="panel-title">Форма обратной связи</h3>
          </div>
          <!-- Содержимое контейнера -->
          <div class="panel-body">

            <!-- Сообщение, отображаемое в случае успешной отправки данных -->
            <div class="alert alert-success hidden" role="alert" id="successMessage">
              <strong>Внимание!</strong> Ваше сообщение успешно отправлено.
            </div>

            <!-- Форма обратной связи -->
            <form id="contactForm">
              <div class="row">

                
                <div id="error" class="col-sm-12" style="color: #ff0000; margin-top: 5px; margin-bottom: 5px;"></div>
                
                <!-- Имя и email пользователя -->                
                <div class="col-sm-6">
                  <!-- Имя пользователя -->
                  <div class="form-group has-feedback">
                    <label for="name" class="control-label">Введите ваше имя:</label>
                    <input type="text" id="name" name="name" class="form-control" required="required" value="" placeholder="Например, Иван Иванович" minlength="2" maxlength="30">
                    <span class="glyphicon form-control-feedback"></span>
                  </div>
                </div>
                <div class="col-sm-6">
                  <!-- Email пользователя -->
                  <div class="form-group has-feedback">
                    <label for="email" class="control-label">Введите адрес email:</label>
                    <input type="email" id="email" name="email" class="form-control" required="required"  value="" placeholder="Например, ivan@mail.ru" maxlength="30">
                    <span class="glyphicon form-control-feedback"></span>
                  </div>
                </div>
              </div>

              <!-- Сообщение пользователя -->
              <div class="form-group has-feedback">
                <label for="message" class="control-label">Введите сообщение:</label>
                <textarea id="message" class="form-control" rows="3" placeholder="Введите сообщение от 20 до 500 символов" minlength="20" maxlength="500" required="required"></textarea>
              </div>

              <hr>
              <!-- Изображение, содержащее код капчи -->		  
	            <img id="img-captcha" src="/feedback/captcha.php">
              <!-- Элемент, обновляющий код капчи -->
	            <div id="reload-captcha" class="btn btn-default"><i class="glyphicon glyphicon-refresh"></i> Обновить</div>
	            <!-- Блок для ввода кода капчи -->
	            <div class="form-group has-feedback">
                <label id="label-captcha" for="captcha" class="control-label">Пожалуйста, введите указанный на изображении код:</label>
	              <input id="text-captcha" name="captcha" type="text" class="form-control" required="required" value="" autocomplete="off" minlength="6" maxlength="6">
	              <span class="glyphicon form-control-feedback"></span>
              </div>

              <!-- Кнопка, отправляющая форму -->  
              <button type="submit" class="btn btn-primary pull-right">Отправить сообщение</button>
            </form><!-- Конец формы -->

          </div>
        </div><!-- Конец контейнера -->

      </div>
    </div>
  </div>

  <script src="/feedback/js/jquery-3.1.0.min.js"></script>
  <script src="/feedback/js/bootstrap.min.js"></script>
  <script src="/feedback/script.js"></script>
</body>
</html>

Формирование изображения, содержащего код капчи, выполняется серверным скриптом captcha.php.

Более подробно познакомиться с тем как работает капча можно в статье Создание капчи на PHP.

PHP код файла captcha.php:

<?php
// открываем сессию
session_start();
 // присваиваем PHP переменной captchastring строку символов
$captchastring = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz';
// получаем первые 6 символов после их перемешивания с помощью функции str_shuffle
$captchastring = substr(str_shuffle($captchastring), 0, 6);
// инициализация переменной сессии с помощью сгенерированной подстроки captchastring, содержащей 6 символов
$_SESSION["code"] = $captchastring;
// генерируем CAPTCHA
// создаем новое изображение из файла background.png 
$image = imagecreatefrompng(dirname(__FILE__).'/background.png');
// устанавливаем цвет (R-200, G-240, B-240) изображению, хранящемуся в $image
$colour = imagecolorallocate($image, 200, 240, 240);
// присваиваем переменной font название шрифта
$font = dirname(__FILE__).'/oswald.ttf';
// устанавливаем случайное число между -10 и 10 градусов для поворота текста 
$rotate = rand(-10, 10);
// рисуем текст на изображении шрифтом TrueType (1 параметр - изображение ($image), 
// 2 - размер шрифта (18), 3 - угол поворота текста ($rotate), 
// 4, 5 - начальные координаты x и y для текста (18,30), 6 - индекс цвета ($colour),
// 7 - путь к файлу шрифта ($font), 8 - текст ($captchastring) 
imagettftext($image, 18, $rotate, 28, 32, $colour, $font, $captchastring);
// передавать изображение будем в формате png
header('Content-type: image/png');
// выводим изображение
imagepng($image);
?>

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

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

Заполненная форма обратной связи
Заполненная форма обратной связи

Отправкой данных на сервер занимается скрипт javascript. Но перед тем как данные передать серверу по технологии AJAX, он должен проверить их на корректность.

Все действия по обработке формы в браузере, а также обновление страницы после получения ответа от сервера выполняет код JavaScript, находящийся в файле script.js.

JavaScript (jQuery) код файла script.js:

// после загрузки веб-страницы
$(function() {

  // при нажатии на кнопку Обновить
  $("#reload-captcha").click(function() {
	// выводим новый код капча
    $('#img-captcha').attr('src','/feedback/captcha.php?id='+Math.random()+'');
  });

  // при отправке формы contactForm на сервер (id="contactForm")
  $('#contactForm').submit(function(event) {
    // отменяем стандартное действие браузера
    event.preventDefault();
    // заводим переменную, которая будет говорить о том валидна форма или нет
    var formValid = true;
    // перебираем все элементы управления формы (input и textarea) 
    $('#contactForm input,textarea').each(function() {
      // проверяем, является ли данный элемент капчей
      // если это так, то не выполняем его проверку
      if ($(this).attr('id') == 'text-captcha') { return true; }
      // находим предков, имеющих класс .form-group (для установления success/error)
      var formGroup = $(this).parents('.form-group');
      // находим glyphicon (иконка успеха или ошибки)
      var glyphicon = formGroup.find('.form-control-feedback');
      // выполняем валидацию данных с помощью HTML5 функции checkValidity
      if (this.checkValidity()) {
        // добавляем к formGroup класс .has-success и удаляем .has-error
        formGroup.addClass('has-success').removeClass('has-error');
        // добавляем к glyphicon класс .glyphicon-ok и удаляем .glyphicon-remove
        glyphicon.addClass('glyphicon-ok').removeClass('glyphicon-remove');
      } else {
        // добавляем к formGroup класс .has-error и удаляем .has-success
     	formGroup.addClass('has-error').removeClass('has-success');
	    // добавляем к glyphicon класс glyphicon-remove и удаляем glyphicon-ok
	    glyphicon.addClass('glyphicon-remove').removeClass('glyphicon-ok');
	    // если элемент не прошёл проверку, то отмечаем форму как не валидную 
	    formValid = false;  
      }
    });
    // проверяем элемент, содержащий код капчи
    // получаем значение элемента input, который содержит код капчи
    var captcha = $("#text-captcha").val();
    // если количество символов в коде капчи не равна 6,
  	// то отмечаем капчу как не валидную и не отправляем форму на сервер
    if (captcha.length!=6) {
	  // получаем элемент, содержащий капчу
      inputCaptcha = $("#text-captcha");
	  // находим предка, имеющего класс .form-group (для установления success/error)
      formGroupCaptcha = inputCaptcha.parents('.form-group');
	  // находим glyphicon (иконка успеха или ошибки)
      glyphiconCaptcha = formGroupCaptcha.find('.form-control-feedback');
	  // добавляем к formGroup класс .has-error и удаляем .has-success
      formGroupCaptcha.addClass('has-error').removeClass('has-success');
	  // добавляем к glyphicon класс glyphicon-remove и удаляем glyphicon-ok
      glyphiconCaptcha.addClass('glyphicon-remove').removeClass('glyphicon-ok');
    }
    // если форма валидна и длина капчи равно 6 символам, то отправляем форму на сервер (AJAX)
    if (formValid && captcha.length==6) {
	  //получаем имя, которое ввёл пользователь	
	  var name = $("#name").val();
	  //получаем email, который ввёл пользователь
      var email = $("#email").val();
	  //получаем сообщение, которое ввёл пользователь
      var message = $("#message").val();
	  //получаем капчу, которую ввёл пользователь
      var captcha = $("#text-captcha").val();

      // объект, посредством которого будем кодировать форму перед отправкой её на сервер
      var formData = new FormData();
      // добавить в formData значение 'name'=значение_поля_name
      formData.append('name', name);
      // добавить в formData значение 'email'=значение_поля_email
      formData.append('email', email);
      // добавить в formData значение 'message'=значение_поля_message
      formData.append('message', message);
      // добавить в formData значение 'captcha'=значение_поля_captcha
      formData.append('captcha', captcha);

	  //отправляем данные на сервер (AJAX)
      $.ajax({
		//метод передачи запроса - POST
        type: "POST",
		//URL-адрес запроса 
        url: "/feedback/process.php",
        //передаваемые данные - formData
        data: formData,
        // не устанавливать тип контента, т.к. используется FormData
        contentType: false,
        // не обрабатывать данные formData
        processData: false,
        // отключить кэширование результатов в браузере
        cache: false,
	    	//при успешном выполнении запроса
        success : function(data){

          // разбираем строку JSON, полученную от сервера
          var $data =  JSON.parse(data);
          // устанавливаем элементу, содержащему текст ошибки, пустую строку
          $('#error').text('');

          // если сервер вернул ответ success (данные получены)
          if ($data.result == "success") {

			// скрываем форму обратной связи
            $('#contactForm').hide();
			// удаляем у элемента, имеющего id=successMessage, класс hidden
            $('#successMessage').removeClass('hidden');
          }
          else if ($data.result == "invalidCaptcha") {
            // если сервер вернул ответ invalidcaptcha, то делаем следующее...
            // получаем элемент, содержащий капчу
            inputCaptcha = $("#text-captcha");
            // находим предка, имеющего класс .form-group (для установления success/error)
            formGroupCaptcha = inputCaptcha.parents('.form-group');
            // находим glyphicon (иконка успеха или ошибки)
            glyphiconCaptcha = formGroupCaptcha.find('.form-control-feedback');
            // добавляем к formGroup класс .has-error и удаляем .has-success
            formGroupCaptcha.addClass('has-error').removeClass('has-success');
            // добавляем к glyphicon класс glyphicon-remove и удаляем glyphicon-ok
            glyphiconCaptcha.addClass('glyphicon-remove').removeClass('glyphicon-ok');
            // выводим новый код капчи
            $('#img-captcha').attr('src', '/feedback/captcha.php?id=' + Math.random() + '');
            // устанавливаем полю, с помощью которого осуществляем ввод капчи пустое значение
            $("#text-captcha").val('');
          } else {
            // если сервер вернул ответ error, то делаем следующее...
            $('#error').text('Произошли ошибки при отправке формы на сервер.');
          }
        },
        error: function (request) {
          $('#error').text('Произошла ошибка ' + request.responseText + ' при отправке данных.');
        }        
      });
	}	 
  });
});

Код файла script.js выполняет следующие основные функции:

  • валидация (проверка) полей формы перед отправкой их на сервер;
  • подготовка данных, и их отправка методом POST на сервер;
  • получения ответа от сервера и разбор результата;
  • в случае получения успешного ответа (success): скрытие формы и отображения сообщения об удачной отправке информации;
  • если в качества ответа пришла ошибка (error, invalidCaptcha или др.): отображения пользователю отрицательного результата.
Сообщение, которое выводится пользователю, если данные были успешно отправлены
Сообщение, которое выводится пользователю, если данные были успешно отправлены
Письмо, пришедшее с формы обратной связи
Письмо, пришедшее с формы обратной связи
Содержимое файла message.txt
Содержимое файла message.txt

На сервере обработку форму обратной связи выполняет php файл process.php.

Содержимое файла process.php:

<?php
//открываем сессию
session_start();
// переменная, в которую будем сохранять результат работы
$data['result']='error';

// функция для проверки длины строки
function validStringLength($string,$min,$max) {
  $length = mb_strlen($string,'UTF-8');
  if (($length<$min) || ($length>$max)) {
    return false;
  }
  else {
    return true;
  }
}

// если данные были отправлены методом POST, то...
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    // устанавливаем результат, равный success
    $data['result']='success';
    //получить имя, которое ввёл пользователь
    if (isset($_POST['name'])) {
      $name = $_POST['name'];
      if (!validStringLength($name,2,30)) {
        $data['name']='Поля имя содержит недопустимое количество символов.';   
        $data['result']='error';     
      }
    } else {
      $data['result']='error';
    } 
    //получить email, который ввёл пользователь
    if (isset($_POST['email'])) {
      $email = $_POST['email'];
      if (!filter_var($email,FILTER_VALIDATE_EMAIL)) {
        $data['email']='Поле email введено неправильно';
        $data['result']='error';
      }
    } else {
      $data['result']='error';
    }
     //получить сообщение, которое ввёл пользователь
    if (isset($_POST['message'])) {
      $message = $_POST['message'];
      if (!validStringLength($message,20,500)) {
        $data['message']='Поле сообщение содержит недопустимое количество символов.';     
        $data['result']='error';   
      }      
    } else {
      $data['result']='error';
    } 
    //получить капчу, которую ввёл пользователь
    if (isset($_POST['captcha'])) {
      $captcha = $_POST['captcha'];
    } else {
      $data['result']='error';
    }
    // если не существует ни одной ошибки, то продолжаем... 
    if ($data['result']=='success') {
      //если пользователь правильно ввёл капчу
      if ($_SESSION["code"] != $captcha) {
        // пользователь ввёл неправильную капчу
        $data['result']='invalidCaptcha';
      }
    }
  } else {
    //данные не были отправлены методом пост
    $data['result']='error';
  }    
 
  // дальнейшие действия (ошибок не обнаружено)
  if ($data['result']=='success') {

    //1. Сохранение формы в файл
    $output = "---------------------------------" . "\n";
    $output .= date("d-m-Y H:i:s") . "\n";
    $output .= "Имя пользователя: " . $name . "\n";
    $output .= "Адрес email: " . $email . "\n";
    $output .= "Сообщение: " . $message . "\n";
    if (file_put_contents(dirname(__FILE__).'/message.txt', $output, FILE_APPEND | LOCK_EX)) {
      $data['result']='success';
    } else {
      $data['result']='error';         
    } 

    //2. Отправляем на почту
    // включить файл PHPMailerAutoload.php
    require_once dirname(__FILE__) . '/phpmailer/PHPMailerAutoload.php';
    //формируем тело письма
    $output = "Дата: " . date("d-m-Y H:i") . "\n";
    $output .= "Имя пользователя: " . $name . "\n";
    $output .= "Адрес email: " . $email . "\n";
    $output .= "Сообщение: " . "\n" . $message . "\n";

    // создаём экземпляр класса PHPMailer
    $mail = new PHPMailer;

    $mail->CharSet = 'UTF-8'; 
    $mail->From      = 'email@mysite.ru';
    $mail->FromName  = 'Имя сайта';
    $mail->Subject   = 'Сообщение с формы обратной связи';
    $mail->Body      = $output;
    $mail->AddAddress( 'myemail@mail.ru' );

    // отправляем письмо
    if ($mail->Send()) {
      $data['result']='success';
    } else {
      $data['result']='error';
    }      

  }
  // формируем ответ, который отправим клиенту
  echo json_encode($data);
?>

Данный файл выполняет следующие основные действия:

  • получение значений с элементов формы index.html;
  • верификация данных формы и капчи;
  • в случае успеха: отправка email письма указанному пользователю и сохранение данных, введённых пользователем, в файл message.txt.
  • отправка результата клиенту (успех, ошибка или неверная капча).

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

Принцип работы формы обратной связи
Принцип работы формы обратной связи

Настройка форма обратной связи

Настройка формы, а именно email, на который необходимо отправлять данные, осуществляется посредством редактирования строчек 99-103 (за исключением 102) файла process.php:

$mail->From      = 'email@mysite.ru'; //от кого (email)
$mail->FromName  = 'Имя сайта'; // от кого (имя)
$mail->Subject   = 'Сообщение с формы обратной связи';
$mail->Body      = $output;
$mail->AddAddress( 'myemail@mail.ru' );

Строчка 99 и 100 устанавливает от кого (email и имя) отправлено письмо. Тема email указывается на строчке 101. Адрес, на который будут отправляться сообщения, задаётся в качестве параметра $mail->AddAddress.

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

Если сообщения отправлять на почту не нужно, то эти действия необходимо закомментировать (строчки 86-110) в файле process.php:

Установка формы обратной связи

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

AJAX форма обратной связи

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

Данную форму можно использовать для лендинга (lending), блога, магазина, а также для других типов сайтов.

Демонстрация AJAX (без перезагрузки) формы обратной связи с защитой от спама:

Демо формы обратной связи


Статьи, связанные с этой темой: