Всплывающая форма обратной связи

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

Базой для разработки формы обратной связи, которая будет доступна пользователю внутри модального окна, является проект, который можно открыть по адресу: http://itchief.ru/lessons/php/feedback-form-for-website. Кроме этой ссылки, данный проект также доступен на гитхабе feedback-form.

Представленная в этом проекте форма имеет следующие характеристики:

  • работает на основе технологии ajax, т.е. без перезагрузки страницы;
  • оформление формы выполнено на основе фреймворка Bootstrap 3;
  • наличие капчи, а также прикрепления к форме любого количества файлов (по умолчанию 5);
  • проверка ошибок, как на стороне клиента, так и на стороне сервера;
  • серверная составляющая формы обратной связи работает на php;
  • отправка данных пользователя, включая файлы на почту (файлы можно прикрепить к письму в виде вложения, так и в теле письма с помощью ссылок);
  • сохранение информации, отставленной пользователем, в файл message.txt.

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

  • добавить кнопку, предназначенную для открытия формы в модальном окне;
  • добавить в HTML код структуру модального окна из фреймворка Bootstrap;
  • перенести в тело модального окна HTML код формы обратной связи;
  • добавить в скрипт script.js код, который будет очищать успешную отправленную форму для того, чтобы можно было отправить ещё одну.

Т.е. изменения потребуется внести 2 файла: index.html и script.js.

HTML файл, содержащий форму обратной связи

Откроем файл index.html и внесём в него следующие изменения:

1. Кнопка, для вызова всплывающего окна:

<div class="text-center">
  <!-- Кнопка, для открытия модального окна -->
    <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#feedbackForm">
      Написать сообщение
  </button>
</div>

2. Выезжающее окно:

<!-- Форма обратной связи в модальном окне -->
  <div class="modal fade" id="feedbackForm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
          <h4 class="modal-title" id="myModalLabel">Форма обратной связи</h4>
        </div>
        <!-- Тело модального окна -->        
        <div class="modal-body">
          ...
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>
        </div>
      </div>
    </div>
  </div>

После этого перенесём код формы обратной связи в модальное окно.

В итоге файл index.html будет иметь следующее содержимое:

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>Форма обратной связи</title>
  <link rel="stylesheet" href="/feedback/css/bootstrap.min.css">
  <style>
    input:-webkit-autofill {
        -webkit-box-shadow: 0 0 0 1000px white inset !important;
    }
  </style>
</head>
<body>
  <h1 class="text-center">Форма обратной связи</h1>
  <hr>
  
  <div class="text-center">
    <!-- Кнопка, для открытия модального окна -->
    <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#feedbackForm">
      Написать сообщение
    </button>
  </div>

  <!-- Форма обратной связи в модальном окне -->
  <div class="modal fade" id="feedbackForm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
          <h4 class="modal-title" id="myModalLabel">Форма обратной связи</h4>
        </div>
        
        <div class="modal-body">

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

            <!-- Форма обратной связи -->
            <form id="messageForm" enctype="multipart/form-data">
              <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>
              <!-- Файлы, для прикрепления к форме -->
              <div class="form-group">
                <p style="font-weight: 700;">Прикрепить к сообщению файлы (максимум <span id="countFiles"></span>):</p>
                <!-- Файл -->
                <input type="file" name="images[]">
                <p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>
              </div>
              <hr style="margin-top: 3px; margin-bottom: 3px;">
              <!-- Капча к форме -->
              <!-- Изображение, содержащее код CAPTCHA-->		  
	            <img id="img-captcha" src="/feedback/captcha.php">
              <!--Элемент, запрашивающий новый код CAPTCHA-->
	            <div id="reload-captcha" class="btn btn-default"><i class="glyphicon glyphicon-refresh"></i> Обновить</div>
	            <!--Блок для ввода кода CAPTCHA-->
	            <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="" minlength="6" maxlength="6" autocomplete="off">
	              <span class="glyphicon form-control-feedback"></span>
              </div>
              <!-- Кнопка, отправляющая форму по технологии AJAX -->  
              <button name="send-message" type="submit" class="btn btn-primary pull-right">Отправить сообщение</button>
            </form><!-- Конец формы -->
            <div class="clearfix"></div>

        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>
        </div>
      </div>
    </div>
  </div>

  <script src="/feedback/js/jquery-1.12.4.min.js"></script>
  <script src="/feedback/js/bootstrap.min.js"></script>
  <script src="/feedback/script.js"></script>

</body>
</html>  

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

В файле script.js потребуется внести только одну поправку, которая будет после закрывания модального окна выполнять следующее действие:

// при закрытии модального окна
$('#feedbackForm').on('hidden.bs.modal', function () {
  // если форма обратной связи скрыта, то...
  if ($('#messageForm').is(':hidden')) {
    // отобразить форму обратной связи
    $('#messageForm').show();
    // добавить класс hidden к элементу, имеющего id=msgSubmit
    $('#msgSubmit').addClass('hidden');
    $('#msgSubmit').html('<strong>Внимание!</strong> Ваше сообщение отправлено.');
    var files = $('#messageForm').find('input[type="file"]');
    files.eq(0).val('');
    files.eq(0).next('p').text('');
    for (var i=1; i<files.length; i++) {
      files.eq(i).next('p').remove();
      files.eq(i).remove();
    }
    $('#text-captcha').val('');
    $('#img-captcha').attr('src', '/feedback/captcha.php?id=' + Math.random() + '');
    $('#message').val('');
    $('#name').val('');
    $('#email').val('');
    $('#messageForm input,#messageForm textarea').each(function () {
      //найти предков, имеющих класс .form-group (для удаления success/error)
      var formGroup = $(this).parents('.form-group');
      //найти glyphicon (иконка)
      var glyphicon = formGroup.find('.form-control-feedback');
      //удалить у элемента formGroup класс .has-success и .has-error
      formGroup.removeClass('has-success').removeClass('has-error');
      //удлаить у элемента glyphicon класс .glyphicon-ok и .glyphicon-remove
      glyphicon.removeClass('glyphicon-ok').removeClass('glyphicon-remove');
   });      

  }
});

Т.е. проверять, успешно ли отправлена форма, и если это так, то очищать её.

Суммарный код файла script.js:

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

  // максимальное количество файлов 
  var countFiles = 5;
  // типы разрешённых файлов
  var typeFile = 'image.*';
  // максимльный размер
  var maxSizeFile = 524288; //512 Кбайт
  // отображаем на форме максимальное количество файлов
  $('#countFiles').text(countFiles);
  // при изменения значения элемента "Выбрать файл"
  $(document).on('change','input[name="images[]"]',function(e){
    // если выбран файл, то добавить ещё элемент "Выбрать файл"
    if ((e.target.files.length>0)&&($(this).next('p').next('input[name="images[]"]').length==0) && ($('input[name="images[]"]').length<countFiles)) {
      $(this).next('p').after('<input type="file" name="images[]"><p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>');
    }
    // если выбран файл, то..
    if (e.target.files.length>0) {
      // получить файл
      var file = e.target.files[0];
      // проверить размер файла
      if (file.size>maxSizeFile) {
        $(this).next('p').text('* Файл не будет отправлен, т.к. его размер больше 512Кбайт');
      }
      // проверить тип файла
      else if (!file.type.match(typeFile)) {
        $(this).next('p').text('* Файл не будет отправлен, т.к. его тип не соответствует разрешённому');
      }
      else {
        // убираем сообщение об ошибке
        if ($(this).next('p')) {
          $(this).next('p').text('');
        }
      }
    }
    else {
      // если после изменения файл не выбран, то сообщаем об этом пользователю
      $(this).next('p').text('* Файл не будет отправлен, т.к. он не выбран');
    }
  });

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

  // при отправке формы messageForm на сервер (id="messageForm")
  $('#messageForm').submit(function (event) {
    // отменим стандартное действие браузера
    event.preventDefault();
    // заведём переменную, которая будет говорить о том валидная форма или нет
    var formValid = true;

    // перебирём все элементы управления формы (input и textarea) 
    $('#messageForm input,#messageForm 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;
      }
    });

    //проверяем элемент, содержащий код капчи
    //1. Получаем значение элемента input, содержащего код капчи
    var captcha = $("#text-captcha").val();
    //2. Если длина кода капчи, которой ввёл пользователь не равно 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 файлы
      // получить все элементы с атрибутом name="images[]"
      var images = document.getElementsByName("images[]");
      // перебрать все элементы images с помощью цикла
      for (var i = 0; i < images.length; i++) {
        // получить список файлов элемента input с type="file"
        var fileList = images[i].files;
        // если элемент не содержит файлов, то перейти к следующей
        if (fileList.length > 0) {
          // получить первый файл из списка
          var file = fileList[0];
          // проверить тип файла и размер
          if ((file.type.match('image.*')) && (file.size<524288)) {
            // добавить его (файл (file) с именем file.name) в formData
            formData.append('images[]', file, file.name);
            console.log(file);
          }
        }
      }
      // добавить в formData значение 'captcha'=значение_поля_captcha
      formData.append('captcha', captcha);

      // технология AJAX 
      $.ajax({
        //метод передачи запроса - POST
        type: "POST",
        //URL-адрес запроса 
        url: "/feedback/verify.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") {
            // скрываем форму обратной связи
            $('#messageForm').hide();
            // удаляем у элемента, имеющего id=msgSubmit, класс hidden
            $('#msgSubmit').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('Произошли ошибки при отправке формы на сервер.');
            if ($data.files) {
              $('#error').html($('#error').text()+'<br>'+$data.files);
            }
          }
        },
        error: function (request) {
          $('#error').text('Произошла ошибка ' + request.responseText + ' при отправке данных.');
        }
      });
    }
  });

  // при закрытии модального окна
  $('#feedbackForm').on('hidden.bs.modal', function () {
    // если форма обратной связи скрыта, то...
    if ($('#messageForm').is(':hidden')) {
      // отобразить форму обратной связи
      $('#messageForm').show();
      // добавить класс hidden к элементу, имеющего id=msgSubmit
      $('#msgSubmit').addClass('hidden');
      $('#msgSubmit').html('<strong>Внимание!</strong> Ваше сообщение отправлено.');
      var files = $('#messageForm').find('input[type="file"]');
      files.eq(0).val('');
      files.eq(0).next('p').text('');
      for (var i=1; i<files.length; i++) {
        files.eq(i).next('p').remove();
        files.eq(i).remove();
      }
      $('#text-captcha').val('');
      $('#img-captcha').attr('src', '/feedback/captcha.php?id=' + Math.random() + '');
      $('#message').val('');
      $('#name').val('');
      $('#email').val('');
      $('#messageForm input,#messageForm textarea').each(function () {
        //найти предков, имеющих класс .form-group (для удаления success/error)
        var formGroup = $(this).parents('.form-group');
        //найти glyphicon (иконка)
        var glyphicon = formGroup.find('.form-control-feedback');
        //удалить у элемента formGroup класс .has-success и .has-error
        formGroup.removeClass('has-success').removeClass('has-error');
        //удлаить у элемента glyphicon класс .glyphicon-ok и .glyphicon-remove
        glyphicon.removeClass('glyphicon-ok').removeClass('glyphicon-remove');
     });      
    }
  });
});

Скачать форму обратной связи

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

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

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

1. Страница, содержащая кнопку, посредством которой вызвается выезжающая контактная форма:

Кнопка, вызывающая всплывающую форму обратной связи

2. Контактная форма в модальном окне (всплывающая):

Форма обратной связи в модальном окне

3. Пользователь неправильно ввёл капчу и нажал на кнопку "Отправить сообщение":

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

4. Успешная отправка формы feedback:

Сообщение об успешной отправки формы обратной связи

5. Письмо, пришедшее менеджеру с формы feedback:

Письмо, пришедшее пользователю посредством формы обратной связи



   PHP 0    2170 +2

Комментарии (43)

  1. Александр Юркин # 0
    Тут бы тоже был бы не плох вариант использования Гугловой ReCaptcha
    1. Александр Мальцев # 0
      Немного позже добавлю как вариант.
    2. Александр # 0
      Форма работает только письма ходят в таком виде
      1. Александр Мальцев # 0
        Исходные коды поправил.
        Необходимо добавить кодировку после создания экземпляра класс PHPMailer в файле verify.php:
        // создаём экземпляр класса PHPMailer
        $mail = new PHPMailer;
        $mail->CharSet = 'UTF-8';  
        
        1. Александр # 0
          Спасибо, вот теперь все правильно отображается
      2. Александр Юркин # 0
        upd:

        В таком виде письма отображаются и почтовым клиентом (Outlook 2013) и через веб интерфейс почты RoundCube.
        На почтовом сервере настроена автоматическая пересылка на Яндекс почту. Яндекс почта показывает нормально.
        1. Александр # 0
          Александр, приветствую, еще раз.
          Появился такой вопрос.
          Допустим на странице есть 5 «разных кнопок», вызывающих форму, например:
          1. Телевизор
          2. Пылесос
          3. Утюг
          4. Чайник
          5. Выбрать
          Чего-бы хотелось:
          1. При кликах по кнопкам с 1-4, появляется форма в которой не надо выбирать чего запрашивать и форма отправляет информацию о том, что запросили например чайник.
          2. При клике по 5й кнопке, появляется форма с селектом, где можно выбрать один или несколько из первых 4х вариантов.

          Возможно-ли это реализовать в рамках одного модального окна и как это сделать?
          1. Александр Мальцев # 0
            Привет. Конечно можно. Создавать кучу модальных окон — это вообще не правильный подход.

            Добавляем в файл index.html необходимые кнопки (например, с data атрибутом data-argument):
            <!-- Кнопки, для открытия модального окна -->
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#feedbackForm" data-argument="Телевизор">
              Телевизор
            </button>
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#feedbackForm" data-argument="Пылесос">
              Пылесос
            </button>
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#feedbackForm" data-argument="Утюг">
              Утюг
            </button>
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#feedbackForm" data-argument="Чайник">
              Чайник
            </button>
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#feedbackForm">
              Выбрать
            </button>
            
            Добавить в форму соответствующее поле:
            <div class="col-sm-6">
              <!-- Продукт -->
              <div class="form-group has-feedback">
                <label for="product" class="control-label">Товар:</label>
                <select id="product" name="product" class="form-control">
                </select>
                <span class="glyphicon form-control-feedback"></span>
              </div>
            </div>
            
            В файл script.js после строчек
            //после загрузки веб-страницы
            $(function () {
            
            следующий код:
            $('button[data-target="#feedbackForm"]').each(function(){
              if ($(this).attr('data-argument')) {
                $('#product').append('<option>'+$(this).attr('data-argument')+'</option>');
              }
            });
            
            $('#feedbackForm').on('show.bs.modal', function (e) {
              if ($(e.relatedTarget).attr('data-argument')) {
                $('#product').val($(e.relatedTarget).attr('data-argument'));
                $('#product').prop('disabled',true);
              }   
            });
            
            Первая часть кода после загрузки страницы наполняет select необходимыми option.
            Вторая часть будет при открытии модального окна определять то, с помощью какой кнопки его открыли и устанавливать в option необходимое значение, если конечно оно есть у кнопки или предлагать выбор.

            Также соответственно добавить в script.js данные для отправки на сервер:
            // получаем выбранный продукт
            var product = $("#product").val();
            // добавить в formData значение 'product'=значение_поля_product
            formData.append('product', product);
            
            И наконец, в файле verify.php получить эти данные $_POST['product'] и отправить на почту.
            Ссылка на готовый пример: yadi.sk/d/xXAeSs3xua5zb
          2. Александр # 0
            Благодарю. Форма формируется, но с небольшим нюансом.
            Если пощелкал сначала по кнопкам с 1 по 4, то при щелчке по 5 кнопке (свободный выбор) селект на форме блокированный, не дает выбирать ничего, а отображает последнее значение data-argument по которому кликали.
            1. Александр Мальцев # 0
              В файле script.js измените код
              $('#feedbackForm').on('show.bs.modal', function (e) {
                if ($(e.relatedTarget).attr('data-argument')) {
                  $('#product').val($(e.relatedTarget).attr('data-argument'));
                  $('#product').prop('disabled',true);
                }   
              });
              
              на
              $('#feedbackForm').on('show.bs.modal', function (e) {
                if ($(e.relatedTarget).attr('data-argument')) {
                  $('#product').val($(e.relatedTarget).attr('data-argument'));
                  $('#product').prop('disabled',true);
                } else {
                  $('#product').prop('disabled',false);  
                  $('#product').prop('selectedIndex',-1);
                }
              });
              
              1. Александр # 0
                Отлично. Благодарю.
                1. Александр # 0
                  Приветствую, снова вынужден обращаться.
                  Этот вариант отлично работает в автономном режиме.
                  Пытаюсь прикрутить его к сайту на joomla.
                  почему-то функция
                  $('#feedbackForm').on('show.bs.modal', function (e) {
                    if ($(e.relatedTarget).attr('data-argument')) {
                      $('#product').val($(e.relatedTarget).attr('data-argument'));
                      $('#product').prop('disabled',true);
                    } else {
                      $('#product').prop('disabled',false);  
                      $('#product').prop('selectedIndex',-1);
                    }
                  });
                  не отрабатывает, отображает полный список, всегда при нажатии на любую кнопку.
                  посмотрел, в «автономном режиме» и на «joomla сайте», подключены одинаковые версии jQuery и BS.
                  В чем может быть проблема?
                  1. Александр Мальцев # 0
                    Попробуйте поместить этот код в блок:
                    jQuery(function($) {
                    
                    });
                    
                    1. Александр # 0
                      Отлично.
                      Благодарю.
            2. Виталий # 0
              Доброй ночи Александр.
              Форму с трудом вписал(не очень опытен). Визуально всё работает и устраивает.
              После заливки на сервер, при обработке введённых данных и отправке
              получаем ответом с сервера код html прям в форму:
              itchief.ru/assets/uploadify/8/8/f/88fe5b7b9a925768c4f713af00daa84e.jpg
              т.е.
              itchief.ru/assets/uploadify/1/9/f/19f679297031a70be9980fb59bb9641f.jpg

              я в сильном замешательстве)
              1. Александр Мальцев # 0
                Ошибка 403 может происходить при отсутствии необходимого файла или директории, а также при наличии недостаточных прав. Более детально посмотреть какой приходит ответ (ошибка) от сервера можно в панели разработчика браузера на вкладке Network.
              2. Виталий # 0
                Спасибо за ответ.
                Сайт статичный из 1 страницы, простой html.
                . htaccess присутствует:
                Options Indexes FollowSymLinks
                DirectoryIndex index.html
                AddCharset utf-8 .php .html .js

                Права такие папки 755, файл 644.
                Скрипты другие работают.
                Запись с лога:
                [03/Sep/2016:00:44:02 +0300] «POST /feedback/verify.php HTTP/1.0» 403 2892 «мойсайт.ru/» «Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36»

                Я ещё в большем замешательстве,
                всё больше превосхожу сам себя, зная свои познания в этом деле.
                Знакомый подсказал вставить обратную форму))
                1. Виталий # 0
                  Вкладка Network:
                  itchief.ru/assets/uploadify/d/6/0/d605d3cd992252b69eeca9273065e392.jpg

                  Это сам хостинг не даёт я понял?
                  1. Виталий # 0
                    1. Александр Мальцев # 0
                      А Ваш тариф на reg.ru поддерживает php. Если нет, то форма работать не будет. Единственное решение (если форма обратной связи нужна) – это переход на более дорогой тариф с поддержкой php.
                    2. Виталий # 0
                      Тариф поддерживает php 5.1-5.6.
                      Александр, Ваша форма удобная в редактировании.
                      Убрал капчу, увеличил объём разрешаемых к отправке файлов.
                      Планировал добавить ввод номера тлф.
                      Хотел адаптировать форму к отображению на мобильных устройствах.
                      Попробую ещё поковыряться.
                      Буду писать в тех поддержку.
                      В любом случае спасибо за проделанную работу.
                      1. Виталий # 0
                        Доброй ночи Александр!
                        Проблема разрешилась!
                        Тех поддержка REGа:
                        «Отключили директиву Options Indexes FollowSymLinks в конфигурационном файле .htaccess»
                        Всё работает, с файлами и без.
                        Осталось поправить кодировку.
                        Огромное спасибо.Ссылка на поддержку сайта есть)
                        1. Александр Мальцев # 0
                          Отлично!
                        2. Александр # 0
                          Александр, приветствую.
                          Можете пояснить, как работает валидация.
                          Я имею ввиду, следующее, какие-то поля формы обязательны для заполнения а какие-то нет.
                          Обязательным полям мы прописываем html атрибут required, а вот дальше… что происходит в js и в php с проверкой полей?
                          То-есть, если допустим поле не обязательное, то как-бы и ни к чему его проверять.
                          Правильно-ли я понимаю, что если мы, например поле message в HTML прописали без required, то в php вместо
                          if (isset($_POST['message'])) {
                                $message = $_POST['message'];
                                if (!validStringLength($message,20,500)) {
                                  $data['message']='Поле сообщение содержит недопустимое количество символов.';
                                  $data['result']='error';
                                }
                              } else {
                                $data['result']='error';
                              }

                          Мы можем просто указать
                          $message = $_POST['message'];

                          и на этом все, или надо еще где-то с чем-то поколдовать?
                          1. Александр Мальцев # 0
                            Здравствуйте.
                            На стороне клиента (браузера) валидацию выполняет сам браузер. Для этого мы используем функцию checkValidity с помощью которой в JavaScript проверяем значение каждого поля формы. Если какое-то из них не прошло проверку, то форму на сервер не отправляем. Для отображения ошибок добавляем классы. Проверку JavaScript выполняет на основании атрибутов required, minlength и др. Т.е. задаём проверку и убираем на стороне клиента с помощью атрибутов HTML элементов. Т.е. проверку не выполняем с помощью специальных плагинов, её осуществляет сам браузер. Но, т.к. проверку на стороне клиента при желании можно обойти, нужна ещё проверка на стороне сервера.
                            На стороне сервера проверка осуществляется так.
                            Но сначала желательно сначала узнать, есть если в массиве $_POST ключ message (чтобы не произошла ошибка):
                            if (isset($_POST['message'])) {
                              $message = $_POST['message'];
                            }
                            
                            Но и дальше по коду (если есть переменная):
                            if (isset($message)) {
                              // что-то делаем с переменной $meassage
                            }
                            
                            1. Александр # 0
                              Благодарю.
                          2. Роман # 0
                            Здравствуйте. Я новичок в этом деле. Пытаюсь вставить кнопку для вызова модальной формы на свою страничку. Ничего не получается. Как это сделать?
                            1. Александр Мальцев # 0
                              Необходимо просто скачать необходимые файлы (bootstrap) и подключить их к странице.
                              Если не знаете как это делать, то почитайте следующие статьи:
                              Установка платформы Twitter Bootstrap
                              Как создавать модальные окна
                            2. Виктор # 0
                              Спасибо за форму.
                              У меня вопрос, Куда вписывать свой email куда должны приходить письма.
                              1. Александр Мальцев # 0
                                Для этого необходимо открыть файл verify.php и указать в AddAddress необходимый email:
                                $mail->AddAddress('myemail@mail.ru');
                                
                              2. Виктор # 0
                                Александр большое Спасибо за ответ!

                                Есть ещё пару вопрос ((
                                1 — Нужно всю папку feedback-form-in-modal закидывать на хостинг или только можно verify.php и файл капчи?
                                2 — Мне не нужна капча, если я просто удалю, будет ли работать форма?

                                Сейчас пытаюсь отправить сообщение, на почту нечего не приходит и просто перебрасывает на верх страницы.
                                1. Александр Мальцев # 0
                                  Конечно всю папку. По умолчанию данный каталог необходимо переименовать в feedback, т.е. feedback-form-in-modal -> feedback. Расположить данный каталог необходимо в корне сайта. Файл index.html можно перенести в любое необходимое место. Это можно сделать благодаря тому, что в нём все необходимые пути заданы абсолютно (т.е. /feedback/...). После того как вы всё это правильно расположите должно всё заработать.

                                  Если же вы не хотите копировать всю папку, то форму feedback необходимо будет тогда дополнительно настраивать. Например, определять свои стили, js-скрипты, php библиотеки (phpMailer) и др.

                                  Если капча не нужна, то необходимо кроме удаления файлов captcha.php, oswald.ttf и background.png удалить ещё соответствующие строки в файлах script.js и verify.php. Если вам нужна такая сборка (без капчи), то могу её дополнительно предоставить.
                                2. Виктор # 0
                                  Александр буду очень благодарным, если сможете предоставить сборку без капчи.

                                  С уважением Виктор.
                                  1. Александр Мальцев # 0
                                    Сборка контактной формы без капчи: yadi.sk/d/4tlCgbhyzfSL7
                                  2. Виктор # 0
                                    Александр может это важно, но хочу сразу сказать, что сайт собирается на Bootstrap последней версии. Поэтому, не будет ли конфликта, если в папке feedback будут тоже файлы от Bootstrap?
                                    1. Александр Мальцев # 0
                                      Можете подключить файлы Bootstrap своего проекта или эти изменить на последнюю версию.
                                    2. Виктор # 0
                                      Решил пока поставить форму с капчей и капча не отображается, хотя всё сделал как надо. Перекинул всю папку в корень сайта и переименовал её в feedback, создал форму в нужном месте и вот в консоле выдаёт ошибку, что нет файла captcha.php
                                      itchief.ru/assets/uploadify/1/e/c/1ec860d37e55a7f4e5d11d98884f4795.jpg
                                      itchief.ru/assets/uploadify/2/e/b/2ebb020a799ce800c1a58e82bea12b79s.jpg
                                      1. Александр Мальцев # 0
                                        Её необходимо разместить на локальном сервере или хостинге.
                                      2. Виктор # 0
                                        Добрый день Александр!

                                        Спасибо за форму без капчи. Но беда просто. Всё делаю как надо, но видно, что-то делаю не так.
                                        1 — Скачал и переименовал папку 'feedback-form-in-modal-without-captcha' в 'feedback'. Залил в корневую папку сайта.
                                        2 — В файле 'verify.php' в нужном месте прописал свой ящик.
                                        3 — Из файла index.html которая в папке 'feedback', скопировал нужную часть кода с строчки 35 по 83 и вставил в корневом файле сайта index.html в нужном месте (я не делаю форму выпадающей).

                                        После чего обновляю страницу сайта и пытаюсь отправить сообщение. При нажатии на отправить, происходит просто перебрасывания на вверх сайта. Надписи о том, что сообщение отправлено нет, и нет письма на почте.
                                        1. Александр Мальцев # 0
                                          Кроме самой формы необходимо на страницу ещё доавить содержимое файла script.js:
                                          <script src="/feedback/script.js"></script>
                                          
                                          Это необходимо выполнить ниже подключения библиотеки jQuery.
                                        2. Виктор # 0
                                          Ура, всё заработало! Спасибо Вам Александр за терпение!
                                          1. Anna # 0
                                            Александр, добрый день!
                                            У меня вот какой вопрос. На сайте для заказа тура используется простая форма с 2-мя полями — email и имя. Она одна и та же и открывается при нажатии на соответствующие ссылки, размещенные на одной странице. Допустим, ТУРЦИЯ, ИТАЛИЯ и т.д. Могу я как-то передать параметр с названием страны, не делая его select-ом в форме? И не создавая 50 отдельных форм для каждой страны? Этот параметр с названием страны должен отправляться на почту администратору.
                                            Спасибо!
                                            1. Александр Мальцев # 0
                                              Здравствуйте.
                                              Необходимо в JavaScript определить текст ссылки и добавить его в качестве данных для отправки на сервер:
                                              //после загрузки веб-страницы
                                              $(function () {
                                                // переменная, которая будет содержать название страны
                                                var country;
                                                // при открытии модального окна с формой получаем текст ссылки (страну)
                                                $('#feedbackForm').on('show.bs.modal', function (e) {
                                                  country = e.relatedTarget.innerText;
                                                });
                                                ...
                                                // добавляем эту информацию в объект FormData (для отправки на сервер)
                                                formData.append('country', country);	
                                              
                                              После этого в php (на сервере) получаем название страны:
                                              $_POST['country']
                                              

                                            Вы должны авторизоваться, чтобы оставлять комментарии.