Добавление Google reCAPTCHA к PHP форме

Добавление Google reCAPTCHA к PHP форме
Содержание:
  1. Что такое Google reCAPTCHA?
  2. Подключение reCAPTCHA v2 или v3
  3. Получение ключей reCAPTCHA
  4. Установка recaptcha на сайт
  5. Готовая форма обратной связи с recaptcha
  6. Комментарии

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

Что такое Google reCAPTCHA?

Google reCAPTCHA – это сервис для защиты вашего сайта от ботов и других атак.

Формы обратной связи, комментирования, регистрации, авторизации, оформление заказа довольно часто подвергаются спам атаке. Чтобы их защитить от ботов и злоупотребление можно воспользоваться reCAPTCHA.

Сайт Google reCAPTCHA

Версии Google reCAPTCHA:

  • reCAPTCHA v2 – проверка пользователя с нажатием на флажок «Я не робот» («I'm not a robot»), бесплатно до 1 млн проверок в месяц;
  • reCAPTCHA v3 – проверка пользователя в фоновом режиме не требующая от него никаких действий (бесплатно до 1 млн запросов в месяц);
  • reCAPTCHA Enterprise – предназначена для комплексной защиты всего сайта от мошеннических действий (версия платная, ориентировочная стоимость около 1$ за 1000 запросов).

Подключение reCAPTCHA v2 или v3

Установку Google reCAPTCHA v2 или v3 для проверки форм можно представить в виде следующих шагов:

  • получение ключей (site и secret) для сайта;
  • вставка виджета и скриптов гугл капчи на HTML страницу;
  • передача ответа на сервер;
  • получение на сервере результата решения капчи.

Получение ключей reCAPTCHA

Получение ключей для reCAPTCHA v2 или v3 необходимо перейти на страницу «www.google.com/recaptcha/admin».

Для доступа к консоли администратора необходимо иметь аккаунт в Gmail. Если учётной записи нет, то её нужно завести.

После этого необходимо нажать на значок «+».

В открывшейся форме нужно:

  • вести название ярлыка (например, Мой сайт);
  • выбрать нужный тип reCAPTCHA;
  • укажите один или несколько доменов (например, «mysite.ru»);
  • принять условия использования reCAPTCHA.

После заполнения всех полей нажать на кнопку «Отправить».

При успешной регистрации Google будут выданы 2 ключа:

  • публичный (его нужно вставить в HTML-код);
  • секретный (на сервере, для установления обмена данными между сайтом и сервисом reCAPTCHA, т.е. для получения ответа о результатах решения капчи пользователем);
Публичный и секретный ключи reCaptcha

Установка recaptcha на сайт

Подключение reCAPTCHA к сайту (странице) осуществляется как на стороне клиента (в HTML), так на стороне сервера (в PHP).

Разберём, как это осуществляется более подробно. В качестве примере выберем ajax форму обратной связи.

Подключение recaptcha к HTML-документу

Подключение виджета reCAPTCHA к странице осуществляется посредством выполнения 2 действий:

  1. Включения в страницу JavaScript скрипта recaptcha.
  2. Добавление элемента div с классом "g-recaptcha" и атрибутом data-sitekey, имеющий в качестве значения ваш публичный ключ (public key) капчи.

Кроме этого, добавим на страницу ещё элемент div с идентификатором id="recaptchaError". Данный элемент будем использовать для отображения ошибки, связанной с google racaptcha.

<!-- добавление элемента div -->
<div class="g-recaptcha" data-sitekey="6KepjAsTFFFFFFMqccY0ZiGqc3TEd3YVxo8cHsGX"></div>

<!-- элемент для вывода ошибок -->
<div class="text-danger" id="recaptchaError"></div>

<!-- js-скрипт гугл капчи -->
<script src='https://www.google.com/recaptcha/api.js'></script>

Кроме этого необходимо будет внести ещё изменения в файл script.js, т.к. форма обратной связи отправляется на сервер через AJAX.

// Работа с виджетом recaptcha
// 1. Получить ответ гугл капчи
var captcha = grecaptcha.getResponse();

// 2. Если ответ пустой, то выводим сообщение о том, что пользователь не прошёл тест.
// Такую форму не будем отправлять на сервер.
if (!captcha.length) {
  // Выводим сообщение об ошибке
  $('#recaptchaError').text('* Вы не прошли проверку "Я не робот"');
} else {
  // получаем элемент, содержащий капчу
  $('#recaptchaError').text('');
}

// 3. Если форма валидна и длина капчи не равно пустой строке, то отправляем форму на сервер (AJAX)
if ((formValid) && (captcha.length)) {
  ...
  // добавить в formData значение 'g-recaptcha-response'=значение_recaptcha
  formData.append('g-recaptcha-response', captcha);
  ...
}

// 4. Если сервер вернул ответ error, то делаем следующее...
// Сбрасываем виджет reCaptcha
grecaptcha.reset();
// Если существует свойство msg у объекта $data, то...
if ($data.msg) {
  // вывести её в элемент у которого id=recaptchaError
  $('#recaptchaError').text($data.msg);
}

Интегрирование recaptcha в php скрипт

Установка recaptcha в скрипт php осуществляется посредством внесения в файл process.php следующих изменений:

  • создание переменной $secret, содержащей секретный ключ вашего сайта;
  • подключения клиентской библиотеки reCAPTCHA PHP посредством включения в скрипт файла autoload.php;
  • проверка наличия ключа g-recaptcha-response в суперглобальном массиве POST;
  • если данное имя (g-recaptcha-response) есть, то создать экземпляр службы recaptcha, используя ваш секретный ключ;
  • получить результат проверки кода: если результат положительный, то выполнить необходимые действия (например, отправить информацию на почту).
  • если возникла ошибка, то отправить клиенту отрицательный результат.
// ваш секретный ключ
$secret = '6NepjAsGBBABBN7_Qy9yfzShcKmc70X2kXQyX1WO';
// однократное включение файла autoload.php (клиентская библиотека reCAPTCHA PHP)
require_once (dirname(__FILE__).'/recaptcha/autoload.php');
// если в массиве $_POST существует ключ g-recaptcha-response, то...
if (isset($_POST['g-recaptcha-response'])) {
  // создать экземпляр службы recaptcha, используя секретный ключ
  $recaptcha = new \ReCaptcha\ReCaptcha($secret);
  // получить результат проверки кода recaptcha
  $resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
  // если результат положительный, то...
  if ($resp->isSuccess()){
    // действия, если код captcha прошёл проверку
    //...
  } else {
    // иначе передать ошибку
    $errors = $resp->getErrorCodes();
    $data['error-captcha']=$errors;
    $data['msg']='Код капчи не прошёл проверку на сервере';
    $data['result']='error';
  }

} else {
  //ошибка, не существует ассоциативный массив $_POST["send-message"]
  $data['result']='error';
}

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

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

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

Изображения готовой формы, в которую интегрирована recaptcha.

Форма обратной связи с recaptcha Заполненная форма обратной связи с recaptcha Результат, который будет отображён при удачной обработке формы на сервере

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

Комментарии: 229

Андрей
Андрей
Приветствую. В скачанной форме долго пытался разобраться, но так и не постиг как производится проверка полей по символам и где редактируются сообщение о неправильно заполненных полях, типа «Заполните это поле» и т.п… Подскажите плз. )
Андрей
Андрей
О, разобрался. Это стандартная функция HTML5 )
linke
linke
Здравствуйте!
У вас отличная форма, понятная. Но никак не получается настроить отправку через smtp. Пробовал через серверы mail и yandex.
Если указываю smtp.yandex.ru порт 465, то в message.txt запись появляется, а на почну не уходит сообщение. И выводится в форме ошибка: 504 Gateway Time-out при отправке данных.
Если указывать ssl://smtp.yandex.ru порт 465, то на почту сообщение не приходит, и выводится сообщение в форме: «Произошла ошибка при отправке формы на сервер.»

Уточните, пожалуйста, в чем может быть ошибка?
Cergey
Cergey
Преведствую, Вас Александр! Внедрил на сайт сие чудо творение!!! Все четко и слаженно работает! Вам огромная благодарнность за Ваши труды! Могли бы Вы помочь в доработке? А именно: подключить валидацию имени, e-mail, а также № тел — что бы могли вписывать не совсем умные, то есть просто набирать цифры, а символы и пробелы должны подставлятся автоматом с формы. как реализовать checkbox или другой вариант — возможность указать не только URL, а и возможность вставки URL страницы соцсети по клику или… варианты?

$bodyMailadmin = str_replace('%email.title%', 'Сообщение для обмена',$bodyMailadmin);
$bodyMailadmin = str_replace('%username%', $name, $bodyMailadmin);
$bodyMailadmin = str_replace('%email.message%', $message, $bodyMailadmin);
$bodyMailadmin = str_replace('%useremail%', $email, $bodyMailadmin);
$bodyMailadmin = str_replace('%userphone%', $phone, $bodyMailadmin);
$bodyMailadmin = str_replace('%usersiteurl%', $siteurl, $bodyMailadmin);
$bodyMailadmin = str_replace('%email.date%', date('d.m.Y H:i'), $bodyMailadmin);
$bodyMailadmin = str_replace('%re%', $re, $bodyMailadmin);
Заранее благодарен!
1qaz1qaz
1qaz1qaz
Доброго времени!

У себя на сайте в форме регистрации для валидации использую php либу grecaptcha:
public function ValidateRecaptcha ($sValue)
{
	$secret = Config::Get('recaptcha.secret_key');
	$resp = null;

	if (isset($_POST['g-recaptcha-response'])) {
		$recaptcha = new \ReCaptcha\ReCaptcha($secret);
		$resp = $recaptcha->verify($_POST['g-recaptcha-response'] , $_SERVER['REMOTE_ADDR']);
	}

	if (!$resp->isSuccess()) {
		return $resp->getErrorCodes();
	}

	return true;
}
На самой странице:
<div class="form-group">
	<script>
		var onloadCallback = function() {
			grecaptcha.render('registration-user-captcha', {
				'sitekey' : '{Config::Get('recaptcha.site_key')}',
				'theme' : '{Config::Get('recaptcha.theme')}',
				'error-callback': onSubmit
			});
		};
		var onSubmit = function() { 
			grecaptcha.reset();
		};
    </script>

	<div id="registration-user-captcha"></div>

	<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>

	<p class="help-block">
		<small class="text-danger validate-error-hide validate-error-field-captcha"></small>
	</p>
</div>
В принципе все отлично работает.

Но, к примеру при регистрации юзера после submit формы рекапча валидировалась, а какое-либо поле (логин, e-mail и т.п.) не прошло валидацию.
Юзер исправляет данные. При этом рекапча уже отмечена решенной.
А при повторном submit формы — получаем ошибку валидации timeout-or-duplicate

Погуглив данную ошибку понял, что API рекапчи не позволяет её верифицировать более одного раза по одному и тому же токену.

Думаю, что для решения проблемы, при получении ошибки либо НЕвалидации какого-либо поля нужно перезапускать рекапчу.

Долго гуглил — как я понял через php это не предусмотрено, а через js — grecaptcha.reset();.

Можете помочь советом, как это «прикрутить»?

В документации есть опция error-callback. Может можно решить задействовав её?
Александр Мальцев
Александр Мальцев
Привет! Необходимо вызвать grecaptcha.reset() в коде JavaScript в котором обрабатываете ответ от сервера.
Vladislav
Vladislav
Здравствуйте, актуальная ли статья сейчас? Что-то не могу понять где получать ключи, после нажатия большой кнопки «Get Started» меня перекидывает на страницу console.cloud.google.com, и там меня просят создать какой-то billing аккаунт, правильно ли это? Просто, там связано что-то с облаком, оплатами, кредитами, не понятно для меня всё это.
Александр Мальцев
Александр Мальцев
Привет! Да, статью обновлю в ближайшее время. Немного всё поменялось. Сейчас нужно входить сюда: www.google.com/recaptcha/admin
Vladislav
Vladislav
Благодарю, теперь без проблем поставил. Странно что в оригинале это нигде не найдешь :)
Leopold
Leopold
Подскажите пожалуйста как использовать капчу дважды на одной странице?
У меня разные формы на странице. При отправке первой формы (идет выше в DOM) все прекрасно. При отправке второй формы grecaptcha.getResponse() не получает код капчи и соответственно дальше скрипт не работает
Александр Мальцев
Александр Мальцев
Посмотрите в этой теме: Защита сайта с помощью invisible reCAPTCHA.
В ней имеется раздел «Несколько invisible reCAPTCHA на одной странице». Здесь необходимо будет создать что-то подобное.
e-lub
e-lub
Recapcha нормально работает с contact form 7. Но мне нужно установить ее в вордпрессе на форму комментариев на других страницах сайта. Спам замучал… Как это сделать?
Заранее благодарен.
talants
talants
Добрый день Александр. А как можно сделать простую защиту файла от ботов. Чтобы файл открывалась только после recaptch'и.
zulfukar
zulfukar
Здравствуйте. Я скачал готовую форму обратной связи с recaptcha, создал 2 ключа (Версия 2 – флажок) и прописал в нужные файлы. После отправки выводится «Ваше сообщение отправлено», но на почту ничего не приходит (на странице google.com/recaptcha/admin/site/ прописаны 2 почты, одна на gmail, вторая на mail.ru). В файле message.txt все отправленные сообщения создаются.
Может еще где-то нужно прописать свою почту?
Сайт: new.313news.net — форма в самом низу.
Александр Мальцев
Александр Мальцев
Здравствуйте! Почта настраивается здесь:
// создаём экземпляр класса 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 (isset($files)) {
  foreach ($files as $value) {
  $mail->addAttachment($value);
}
Но, лучше, конечно, это сделать через SMTP. Для этого код, приведённый выше лучше заменить на этот (вместо звёздочек следует установить свои значения):
// устанавливаем параметры
$mail = new PHPMailer;
$mail->CharSet = 'UTF-8';

/* Отправка письма по SMTP */
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->Host = '*****';
$mail->Port = '*****';
$mail->Username = '*****';
$mail->Password = '*****';

$mail->Encoding = 'base64';
$mail->IsHTML(true);
$mail->setFrom('*****', '*****');
$mail->Subject = '*****';
$mail->Body = $output;

$mail->addAddress('*****');

if (isset($files)) {
  foreach ($files as $value) {
    $mail->addAttachment($value);
  }
}
zulfukar
zulfukar
Спасибо за Ваш ответ. Я выбрал отправку по SMTP, но не знаю что прописать вместо ***
Вот данные почты, помогите пожалуйста заполнить.

Имя пользователя: fetva@313news.net
Пароль: Используйте пароль почтовой учетной записи.
Сервер входящей почты: cpanel24.v.fozzy.com
IMAP Port: 993 POP3 Port: 995
Исходящий сервер: cpanel24.v.fozzy.com
SMTP Port: 465
IMAP, POP3 и SMTP authentication.
Александр Мальцев
Александр Мальцев
Попробуйте так:
/* Отправка письма по SMTP */
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->Host = 'cpanel24.v.fozzy.com';
$mail->Port = '465';
$mail->Username = 'fetva@313news.net';
$mail->Password = '*****';

$mail->Encoding = 'base64';
$mail->IsHTML(true);
$mail->setFrom('fetva@313news.net', '313news.net');
$mail->Subject = 'Message from 313news.net';
$mail->Body = $output;

$mail->addAddress('fetva@313news.net');
zulfukar
zulfukar
Письмо не ушло. На почте ничего нет, но в файле message.txt оно появилось.

Через минуту в форме появилось сообщение:
Произошла ошибка <html><head><title>500 Internal Server Error</title></head><body> <h2>Request Timeout</h2> <p>This request takes too long to process, it is timed out by the server. If it should not be timed out, please contact administrator of this web site to increase 'Connection Timeout'. </p> </body></html> при отправке данных.
А вместо капчи написано: Время проверки истекло…

Приведу код на всякий случай
//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 (isset($files)) {
//      foreach ($files as $value) {
//        $mail->addAttachment($value);
//      }
//    }

// устанавливаем параметры
$mail = new PHPMailer;
$mail->CharSet = 'UTF-8';

/* Отправка письма по SMTP */
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->Host = 'cpanel24.v.fozzy.com';
$mail->Port = '465';
$mail->Username = 'fetva@313news.net';
$mail->Password = 'пароль';

$mail->Encoding = 'base64';
$mail->IsHTML(true);
$mail->setFrom('fetva@313news.net', '313news.net');
$mail->Subject = 'Message from 313news.net';
$mail->Body = $output;

$mail->addAddress('fetva@313news.net');

if (isset($files)) {
  foreach ($files as $value) {
    $mail->addAttachment($value);
  }
}

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

  }
zulfukar
zulfukar
Изменил на это и письмо ушло:
Non-SSL Settings (NOT Recommended).
Исходящий сервер: mail.313news.net
SMTP Port: 587
$mail->Host = 'mail.313news.net';
$mail->Port = '587';
Помогите пожалуйста еще в одном деле. Мне нужно добавить в форму и код Селектор.
Вместо поля Имя добавить селектор: Выбрать пол — Мужской, Женский
После поля Текст добавить селектор с выбором сотрудника (на почту отправляется выбранное имя)
Александр Мальцев
Александр Мальцев
SSL можно указать так:
$mail->Host = 'ssl://cpanel24.v.fozzy.com';
Как добавить в форму новое поле подробно описывал в этой статье. Она, конечно, немного отличается от этой, но принцип такой же.
zulfukar
zulfukar
$mail->Host = 'ssl://cpanel24.v.fozzy.com';
с этим вылезла ошибка, письмо не отправляется.

Как добавить в форму новое поле подробно описывал в этой статье. Она, конечно, немного отличается от этой, но принцип такой же.
Я посмотрел и попытался сделать. Добавил в индексный файл

<div class="form-group has-feedback">
<select name="pol" id="pol" required="required">
<option value="">Укажите свой пол</option>
<option value="Мальчик">Мальчик</option>
<option value="Девочка">Девочка</option>
</select>
</div>
а в файл process.php добавил:
перед:
//получить сообщение, которое ввёл пользователь
добавил
if (isset($_POST['pol'])) {
    $message = filter_var($_POST['pol'], FILTER_SANITIZE_STRING); // защита от XSS
    if (!checkTextLength($pol, 3, 10)) { // проверка на количество символов в тексте
        $data['pol'] = 'Поле <b>pol</b> содержит недопустимое количество символов';
        $data['result'] = 'error';
    }
}
далее добавил pol тут
//1. Сохрание формы в файл
    $output = "---------------------------------" . "\n";
    $output .= date("d-m-Y H:i:s") . "\n";
    $output .= "Имя пользователя: " . $name . "\n";
    $output .= "Адрес email: " . $email . "\n";
    $output .= "Пол: " . $pol . "\n";
    $output .= "Сообщение: " . $message . "\n";
и тут
//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 .= "Пол: " . $pol . "\n";
    $output .= "Сообщение: " . "\n" . $message . "\n";
в итоге письмо отправляется, на почту приходит слово Пол, но выбранная опция не приходит.
Я не разбираюсь в php, помогите пожалуйста.
Александр Мальцев
Александр Мальцев
Может порт с использованием ssl какой-то другой.

В этой форме ещё нужно добавить код в «script.js»:
// ...
var pol = $('#pol').val();
// ...
formData.append('pol', pol);
// ...
Alik
Alik
Добрый день.
Спасибо за инструкцию.

Помогите, пожалуйста.
1. Нет файла process.php Где он может лежать? Или его нужно создать?
2. Файл script.js у меня в шаблоне сайта, это нормально, код капчи будет в нем работать?
Спасибо.
Вячеслав
Вячеслав
process.php лежит в корне feedback, там же где и index.html
По: script.js Он может лежать где угодно, главное измените путь под комментарием //URL-адрес запроса
Alik
Alik
Спасибо за ответ.
Странно, прошерстил toal comannder, process.php нет нигде.
У меня cms joomla, может он имеет другое название?
Вячеслав
Вячеслав
А при чем тут joomla? Эта форма не имеет отношения к cms
Скачайте архив и все поймете
Вячеслав
Вячеслав
Здравствуйте Александр.
Спасибо за труды и форму. Все работает отлично.
Не подскажете как добавить 4 input'a radio в вашу форму? Или хотя бы ссылку на мануал для нубов)
Буду очень благодарен.
Александр Мальцев
Александр Мальцев
Здравствуйте! Спасибо за отзыв!
Алгоритм для добавления радиокнопок в форму будет следующий.
1. Добавить переключатели в разметку формы (в «index.html»):
...
<div class="form-group has-feedback">
<p style="margin-bottom: 5px; font-weight: 700;">Выберите цвет:</p>
<div class="radio" style="margin-top: 5px;">
    <label>
    <input type="radio" name="color" value="red" checked>
        Красный
    </label>
</div>
<div class="radio">
    <label>
    <input type="radio" name="color" value="green">
        Зеленый
    </label>
</div>   
<div class="radio">
    <label>
    <input type="radio" name="color" value="white">
        Белый
    </label>
</div>
<div class="radio">
    <label>
    <input type="radio" name="color" value="gold">
        Золотой
    </label>
</div>                                                
</div>
...
2. Включить значение выбранной радиокнопки в FormData (для отправки на сервер). Для этого нужно добавить следующий код в «script.js»:
...
// добавить данные в FormData значение 'color' = значение_поля_color
formData.append('color', $('[name="color"]:checked').val());
...
3. Добавить в «process.php» код для получения значения поля color из POST и включить его значение в данные для отправки на почту:
...
// получим цвет
if (isset($_POST['color'])) {
    $color = $_POST['color'];
} else {
    $data['result']='error';
}    
...
$output .= "Цвет: " . "\n" . $color . "\n";
...
Ссылка на архив: контактная форма с radio
Вячеслав
Вячеслав
Александр Мальцев, спасибо за суету с формой с радио, но я уже разобрался с этим.
Но труды я думаю не напрасны, кому то это пригодится
Alex
Alex
Здравствуйте!

Почему то не отправляются файлы в папку images, ошибку не пишет, просто отправляет сообщение на почту.

Сделал для нескольких типов файлов, как вы писали ниже.

<?php
// открываем сессию
session_start();

// переменная в которую будем сохранять результат работы
$data['result']='error';

// разрешённые типы файлов
$allowedExtension = array(«jpg», «jpeg», «gif», «png», «xls», «xlsx», «zip», «doc», «rar»);

// директория для хранения файлов ()
$pathToFile = $_SERVER['DOCUMENT_ROOT'].'/templates/mysite/feedback/files/';

// максимальный размер файла
$maxSizeFile = 3072000;

// ваш секретный ключ
$secret = '6gfgAAAgM458madp_-Qn9gRPSpmJm';

// функция для проверки длины строки
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') {

$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 ($data['result']=='success') {
// однократное включение файла autoload.php (клиентская библиотека reCAPTCHA PHP)
require_once (dirname(__FILE__).'/recaptcha/autoload.php');
// если в массиве $_POST существует ключ g-recaptcha-response, то…
if (isset($_POST['g-recaptcha-response'])) {
// создать экземпляр службы recaptcha, используя секретный ключ
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
// получить результат проверки кода recaptcha
$resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
// если результат положительный, то…
if ($resp->isSuccess()){
// действия, если код captcha прошёл проверку
//обработаем файлы, загруженные пользователем посредством элементов с name=«images[]»
// если ассоциатианый массив $_FILES[«images»] существует, то
if(isset($_FILES[«images»])) {
// переберём все файлы (изображения)
$files = array();
foreach ($_FILES[«images»][«error»] as $key => $error) {
// если ошибок не возникло, т.е. файл был успешно загружен на сервер, то…
if ($error == UPLOAD_ERR_OK) {
// имя файла на устройстве пользователя
$nameFile = $_FILES['images']['name'][$key];
// расширение загруженного пользователем файла в нижнем регистре
$extFile = mb_strtolower(pathinfo($nameFile, PATHINFO_EXTENSION));
// размер файла
$sizefile = $_FILES['images']['size'][$key];
//myme-тип файла
$filetype = $_FILES['images']['type'][$key];
// проверить расширение файла, размер файла и mime-тип
if (!in_array($extFile, $allowedExtension)) {
$data['files']='Ошибка при загрузке файлов (неверное расширение).';
$data['result']='error';
} elseif ($sizefile > $maxSizeFile) {
$data['files']='Ошибка при загрузке файлов (размер превышает 3МБ).';
$data['result']='error';
} elseif (!in_array($filetype, $allowedExtension)){
$data['files']='Ошибка при загрузке файлов (неверный тип файла).';
$data['result']='error';
} else {
//ошибок не возникло, продолжаем…
// временное имя, с которым принятый файл был сохранён на сервере
$tmpFile = $_FILES['images']['tmp_name'][$key];
// уникальное имя файла
$newFileName = uniqid('img_', true).'.'.$extFile;
// полное имя файла
$newFullFileName = $pathToFile.$newFileName;
// перемещаем файл в директорию
if (!move_uploaded_file($tmpFile, $newFullFileName)) {
// ошибка при перемещении файла
$data['files']='Ошибка при загрузке файлов.';
$data['result']='error';
} else {
$files[] = $newFullFileName;
}
}
} else {
//ошибка при загрузке файл на сервер
$data['result']='error';
}
}
}
} else {
// иначе передать ошибку
$errors = $resp->getErrorCodes();
$data['error-captcha']=$errors;
$data['msg']='Код капчи не прошёл проверку на сервере';
$data['result']='error';
}
} else {
$data['result']='error';
}
}
} else {
//ошибка, не существует ассоциативный массив $_POST[«send-message»]
$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 (isset($files)) {
$output .= «Файлы: ». "\n";
foreach ($files as $value) {
$href = substr($value,strpos($value, '/templates/mysite/feedback/'));
$output .= ''.$href.''. "\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";
if (isset($files)) {
$output .= «Файлы: ». "\n";
foreach ($files as $value) {
$href = substr($value,strpos($value, '/templates/mysite/feedback/'));
$output .= ''.$href.''. "\n";
}
}

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

$mail->CharSet = 'UTF-8';
$mail->From = 'as@3u.ru';
$mail->FromName = 'Админ 3u.ru';
$mail->Subject = 'Письмо с сайт 3u.ru';
$mail->Body = $output;
$mail->IsHTML(true);
$mail->AddAddress( 'My@ya.ru' );
// прикрепляем файлы к письму


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

}

echo json_encode($data);

?>


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

// максимальное количество файлов
var countFiles = 5;
// типы разрешённых файлов
var typeFile = [
'jpg',
'jpeg',
'gif',
'png',
'xls',
'xlsx',
'zip',
'doc',
'rar',
];
// максимльный размер
var maxSizeFile = 3072000; //3 МБ
// отображаем на форме максимальное количество файлов
$('#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('');
}
// если выбран файл, то…
if (e.target.files.length>0) {
// получить файл
var file = e.target.files[0];
// проверить размер файла
if (($.inArray(file.name.split('.').pop().toLowerCase(),typeFile)>=0) && (file.size<3072000)) {
formData.append('images[]', file, file.name);
}
// проверить тип файла
else if ($.inArray(file.name.split('.').pop().toLowerCase(),typeFile)==-1) {
$(this).next('p').text('* Файл не будет отправлен, т.к. его тип не соответствует разрешённому');
}
else {
// убираем сообщение об ошибке
if ($(this).next('p')) {
$(this).next('p').text('');
}
}
}
else {
// если после изменения файл не выбран, то сообщаем об этом пользователю
$(this).next('p').text('* Файл не будет отправлен, т.к. он не выбран');
}
});

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

// перебирём все элементы управления формы (input и textarea)
$('#messageForm input,#messageForm textarea').each(function () {

//найти предков, имеющих класс .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. Получаем капчу
var captcha = grecaptcha.getResponse();
//2. Если длина кода капчи, которой ввёл пользователь не равно 6,
// то сразу отмечаем капчу как невалидную (без отправки на сервер)
if (!captcha.length) {
// Выводим сообщение об ошибке
$('#recaptchaError').text('* Вы не прошли проверку «Я не робот»');
} else {
// получаем элемент, содержащий капчу
$('#recaptchaError').text('');
}

// если форма валидна и длина капчи не равно пустой строке, то отправляем форму на сервер (AJAX)
if ((formValid) && (captcha.length)) {

// получаем имя, которое ввёл пользователь
var name = $("#name").val();
// получаем email, который ввёл пользователь
var email = $("#email").val();
// получаем сообщение, которое ввёл пользователь
var message = $("#message").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);
}
}
}

// добавить в formData значение 'g-recaptcha-response'=значение_recaptcha
formData.append('g-recaptcha-response', captcha);

// технология AJAX
$.ajax({
//метод передачи запроса — POST
type: «POST»,
//URL-адрес запроса
url: "/templates/mysite/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») {
// скрываем форму обратной связи
$('#messageForm').hide();
// удаляем у элемента, имеющего id=msgSubmit, класс hidden
$('#msgSubmit').removeClass('hidden');
} else {
// Если сервер вернул ответ error, то делаем следующее…
$('#error').text('Произошла ошибка при отправке формы на сервер.');
// Сбрасываем виджет reCaptcha
grecaptcha.reset();
// Если существует свойство msg у объекта $data, то…
if ($data.msg) {
// вывести её в элемент у которого id=recaptchaError
$('#msg').text($data.msg);
}
if ($data.files) {
$('#error').html($('#error').text()+'
'+$data.files);
}
}
},
error: function (request) {
$('#error').text('Произошла ошибка ' + request.responseText + ' при отправке данных.');
}
});
}
});
});
Александр Мальцев
Александр Мальцев
Привет! Если изменили форму, то лучше описать что именно? А также что хотите получить в результате?
Код вставлять не нужно. Просто укажите ссылку на архив этой формы, размещённой на каком-нибудь файлохранилище. Но лучше разместить форму на Github, и предоставить ссылку на этот репозиторий. Тогда будут видны изменения. Форма, представленная в статье расположена на Github по этому адресу.
Вячеслав
Вячеслав
Александр, здравствуйте. Спасибо за форму!
Подскажите, как сделать темную капчу?
Dozent
Dozent
Добрый день
из коробки выдаёт Произошла ошибка при отправке данных.

ошибка 500 в нетворке
Александр Мальцев
Александр Мальцев
Добрый. Это может зависеть от настроек веб сервера, а также, например, от того используете ли вы на странице тег base. Проверьте имеется ли доступ из фронтенда к файлу process.php, например, указав путь к нему в адресной строке браузера.
Dozent
Dozent
Доступа нет
{"result":"error"}
сменил версию php на 7
ошибку уже не выдаёт
и при отправке ничего не происходит
Дарьян
Дарьян
Здравствуйте. Я тут форму переделывал под стандарты которые нам прислали. И чего то я поплыл:
1) Не может форма обработать капчу, хотя зареган и прописан открытый и закрытый ключ.
2) У брать капчу не вариант, так как хостинг блочит отправку сообщений без капчи.
Ссылка на код: codepen.io/qasp/pen/MZqOrQ
Вопрос в том чего делать и куда прописать в коде закрытый ключ, так как я уже вставлял в поле объявлений и не помогло?
Спасибо, а то я в скриптах не ахти.
Дарьян
Дарьян
Например если без проверки капчи:

if ($filesize < 10000000) {
mail($to, $subject, $message, $headers);
$output = '';
} else {
$output = '';
}
}

то все нормально, но не отправляет хост без капчи. А с капчей беда беда. Или просто форма вылетает без подтверждений и так или неправильный код, или еще чего хуже стопорится. Вся пробле в том что не могу капчу вклинить правильно.
Владимир
Владимир
Помогите пожалуйста. Капча стоит как будто для красоты на сайте.Код где стоит капча
<?php include «init.php»; ?>
<?php
if(trim($_GET['mode'])=='ajax'){
header('Content-Type: application/json; charset=utf-8');
if(trim($_POST['action'])==htmlspecialchars(trim($_GET['controller']))){
$result=array();
$result['errors']=array();
if(trim($_POST['email'])==''){
$result['errors']['email']=l('register_error_email_empty');
} elseif(!preg_match("/^([-a-zA-Z0-9._]+@[-a-zA-Z0-9.]+(\.[-a-zA-Z0-9]+)+)*$/", trim($_POST['email']))){
$result['errors']['email']=l('register_error_email_invalid');
} elseif(mysql_num_rows(mysql_query(«SELECT * FROM `users` WHERE `email`='»._F($_POST['email'])."';"))){
$result['errors']['email']=l('register_error_email_exists');
}
if(trim($_POST['password'])==''){
$result['errors']['password']=l('register_error_password_empty');
} elseif(mb_strlen(trim($_POST['password']))<6){
$result['errors']['password']=l('register_error_password_short');
}
if(trim($_POST['cpassword'])==''){
$result['errors']['cpassword']=l('register_error_cpassword_empty');
} elseif(mb_strlen(trim($_POST['password']))>=6 && trim($_POST['cpassword'])!=trim($_POST['password'])){
$result['errors']['cpassword']=l('register_error_cpassword_not_equals');
}
if(!isset($_POST['agree'])){
$result['errors']['agree']=l('register_error_agree_off');
}
if(count($result['errors'])==0){
$code=md5(uniqid('').$time);
$create=mysql_query(«INSERT INTO `users` SET `email`='»._F($_POST['email'])."', `register_code`='".$code."', `register_password`='".md5(trim($_POST['password']))."', `time`='".$time."', `active`='0';");
$mail=mysql_fetch_assoc(mysql_query(«SELECT * FROM `mail_templates` WHERE `code`='register';»));
$to=trim($_POST['email']);
$mail['title']=$mail['title_'.$config['lang']];
$mail['body']=$mail['body_'.$config['lang']];
$mail['body']=str_replace('[SITE_NAME]', $config['sitename'], $mail['body']);
$mail['body']=str_replace('[SITE_URL]', $config['siteurl'], $mail['body']);
$mail['body']=str_replace('[ACTIVATION_CODE]', $code, $mail['body']);
liam($to, $mail['title'], $mail['body'], «noreply@».$config['siteurl']);
$result['status']='success';
} else {
$result['status']='error';
}
echo json_encode($result);
}
exit;
}
?>
<?php
$pagetitle=l('register_title')." • ".$config['sitename'];
$pagedesc=$config['description'];
?>
<?php
if($m){ include «m-register.php»; exit; }
?>
<?php include «includes/header.php»; ?>
<?php echo l('register_title'); ?>
<?php echo l('register_type_email'); ?>


<?php echo l('register_type_password'); ?>


<?php echo l('register_retype_password'); ?>


<?php echo l('register_agree'); ?>



<?php echo l('register_submit'); ?>
<?php echo l('register_already_registered'); ?>




 
<?php echo l('register_features'); ?>
<?php echo l('register_feature_1'); ?>
<?php echo l('register_feature_2'); ?>
<?php echo l('register_feature_3'); ?>
<?php echo l('register_features_end'); ?>




<?php include «includes/footer.php»; ?>
[/PHP]
Александр Мальцев
Александр Мальцев
По вашему коду, так, похоже, и есть. В вашем коде нет проверки кода. Смотрите, как сделано в статье и внедряйте что-то подобное.
peitou
peitou
Здравствуйте!
Тестирую форму на локальном сервере (денвер)
Проверки срабатывают, но при нажатии на кнопку «Отправить» ничего не происходит.
Александр Мальцев
Александр Мальцев
Если у вас не появляется сообщение об успешной отправке, то:
— проверьте, ввели ли вы ключи (публичный и секретный) в нужные места формы;
— посмотрите, есть ли ошибки в ответе, который пришёл от сервера после обработки формы.
В Денвере установлена email заглушка, поэтому почтовые сообщения не отправляются. Они просто складываются в некоторую папку.
peitou
peitou
— Публичный ключ ввел в индексе, секретный — в процесс.
— Ругается на 68 строку в Post.php return file_get_contents(self::SITE_VERIFY_URL, false, $context);
— Да, складывает письма в tmp папку.
peitou
peitou
Дело было в настройке https
Roman
Roman
Спасибо за статью и форму. Поставил себе и у меня такой вопрос, сложно ли эту форму переделать для отправки на почту через SMTP?.. Сам не очень разбираюсь в этом, пробовал несколько вариантов, что бы настроить SMTP, письмо никак не отправляется.
Александр Мальцев
Александр Мальцев
В этом комментарии посмотрите ответ.
Roman
Roman
Спасибо, всё настроил. Единственное что, отправляю через почту на хостинге, и время отправки довольно долгое ~10-15 секунд, с вложением на 1 мб. Есть ли смысл настраивать через другие SMTP, такие как мэйл или яндекс?
Александр Мальцев
Александр Мальцев
Не знаю, может хостер такой.
Единственное что не умеют большинство хостеров — это подписывать письма с помощью DKIM. Без этой подписи письма будут попадать большинству пользователей в спам. Если это так, то может и есть смысл настроить почту для домена, например, через Яндекс.
Arkady
Arkady
Самый добрый день! Спасибо вам за инструкции и комплект формы с капчей! Я использую аналогичную уже пару лет, но с недавнего времени она перестала отправлять отзывы с сайта elenaturkka.ru/ord.php, после отправки сообщения появляется надпись «Произошла ошибка при отправке формы на сервер».

В чем может быть проблема? Возможно, это связано с тем, что у Гугла сейчас новая версия рекапчи (V2)?
Алекс
Алекс
Здравствуйте! Подскажите пожалуйста, в чем проблема. Добавил рекапчу в форму авторизации админки, отображается все норм, НО рекапча стоит «для красоты» и я без нее нажатием по кнопке Войти попадаю в админку, как сделать, чтобы кнопка Войти срабатывала только после прохождения рекапчи?

-вид формы авторизации в админку: itchief.ru/assets/uploadify/4/2/b/42b1f14fa230ca225581f8c64d76f0e2.jpeg
-файл login.php выглядит так:
<div class="modal-header">
	<h3 class="modal-title">Логин</h3>
	<p>Войдите используя свои данные</p>
</div>
<div class="modal-body">
<? echo validation_errors(); ?>
<? echo form_open(); ?>
<table class="table">
	<tr>
		<td>Логин:</td>
		<td><? echo form_input('email'); ?></td>
	</tr>
	<tr>
		<td>Пароль:</td>
		<td><? echo form_password('password'); ?></td>
	</tr>
	<tr>
		<td></td>
		<td><div class="g-recaptcha" data-sitekey="6Lc4qTEUAAAAAGZMgx6v6_tNWDD000000000"></div></td></tr>
<tr><td><? echo form_submit('submit','Войти','class="btn btn-primary"'); ?></td>
	</tr>
</table>
<? echo form_close(); ?>
</div>
-файл adm_head.php выглядит так (если он нужен):
<!DOCTYPE html>
<html>
  <head>
    <title><? echo $this->config->item('site_name'); ?> админ-панель</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Bootstrap -->
    <link href="<? echo site_url('/assets/css/bootstrap.min.css'); ?>" rel="stylesheet" media="screen">
    <link href="<? echo site_url('/assets/css/bootstrap-glyphicons.css'); ?>" rel="stylesheet" media="screen">
	<script src="http://code.jquery.com/jquery.js"></script>
	<script type="text/javascript" src="http://code.jquery.com/ui/1.10.0/jquery-ui.js"></script>
	<script type="text/javascript" src="<? echo site_url('/assets/js/tinymce/tinymce.min.js'); ?>"></script>
	<script type="text/javascript" src="<? echo site_url('/assets/js/custom.js'); ?>"></script>
	<script type="text/javascript">
	tinymce.init({
		selector: "textarea.tinymce",
		plugins: [
			"advlist autolink lists link image charmap print preview anchor",
			"searchreplace visualblocks code fullscreen",
			"insertdatetime media table contextmenu paste"
		],
		toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
	});
	</script>
	
	<script type="text/javascript">
	$(document).ready(function() {
	var fixHelper = function(e, ui) {
		ui.children().each(function() {
			$(this).width($(this).width());
		});
		return ui;
	};
    $( ".tblsort tbody" ).sortable({
		helper: fixHelper,
        opacity: 0.8, 
        cursor: 'move', 
        tolerance: 'pointer',  
        items:'tr',
        placeholder: 'state', 
        forcePlaceholderSize: true,
        update: function(event, ui){
            $.ajax({
                url: "/admin/goods/chg_order_ajax",
                type: 'POST',
                data: $(this).sortable("serialize"), 
            });
//-------------------------------                                
            }
                
        });

		$( ".tblsort tbody" ).disableSelection();
	});  
	</script><script src='https://www.google.com/recaptcha/api.js'></script>
 </head>
Алекс
Алекс
попадаем в форму авторизации по ссылке: сайт/admin/user/login
а после авторизации на страницу сайт/admin
PS я не программист, своими силами смог вставить только код рекапчи в форму авторизации, прошу подкорректировать мои данные для нормальной работы.
Александр Мальцев
Александр Мальцев
Вам тут ещё много чего нужно добавлять. Во-первых, вам нужно добавить сессии. А то, как вы будете отличать авторизированного пользователя от посетителя. Во-вторых, рекапча нужна только для защиты от спама. Её проверку нужно добавить в тот же модуль, в котором вы проверяете имя и пароль пользователя…
Ihar
Ihar
Люди отзовитесь, как из этой формы оставить только номер телеона, имя и рекапчу? может быть у кого нибудь есть?
aliska
aliska
вот ссылка на мои файлы: cloud.mail.ru/public/N8sV/uGevwcYaC
Александр Мальцев
Александр Мальцев
Здравствуйте. Спасибо.
Посмотрите, какой ответ вам возвращает сервер (вкладка Network -> process.php -> Response). После этого будет понятно, что у вас работает не так.
aliska
aliska
Здравствуйте. Все оказалось банально: поскольку отправку формы сделал без прикрепления файлов, то сняв проверку (закомментировав 240—248 строки) в файле process.php надпись об ошибке пропала. :)
Ещё раз спасибо за форму и уделённое время!
aliska
aliska
Здравствуйте.
Хорошие формы!
Но столкнулся с проблемой:
Установил эту форму yadi.sk/d/jrEy-35W3LDYk4, после отправки формы пишет «Ошибка! Форму не удалось отправить.» и поля не очищаются, хотя письмо отправителю и мне приходит. В консоли гугла ошибок нет. Как починить, куда копать?
Заранее благодарен!
Алексей
Алексей
Здравствуйте,
столкнулся с проблемой не показывает алерт после отправки. Причем даже на форме которую скачал без изменений. В чем может быть проблема?
Алексей
Алексей
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data[Подробнее] script.js:143:24
Александр Мальцев
Александр Мальцев
Здравствуйте. Вам необходимо определить какие ошибки возникают на сервере. Для этого в браузере необходимо открыть «Инструменты разработчика», перейти на вкладку Network, выбрать запрос process.php и посмотреть ответ (Response).
Алексей
Алексей
Спасибо за совет,
проблема была банальной
на сервере не было объявлено «date_default_timezone_set»
Андрей
Андрей
Здравствуйте!
Интересует вопрос о персональных данных.
В капче они, но они относятся только к Google и нужен дополнительно чекбокс? Или ссылки в капче по сути тоже самое?
Надеюсь понятен вопрос, заранее благодарю за ответ.
yadi.sk/i/KP3HRWEZ3LDQCp
Александр Мальцев
Александр Мальцев
Здравствуйте. Да, нужен дополнительный чекбокс. Те, которые в виджете капчи, относятся к Google.
Алексей
Алексей
Здравствуйте Александр
столкнулся с проблемой в форме. при заполнение поле E-mail вот таким адресом test@test поле проходит валидацию показывает галочку. Но пишет ошибка при отправке письма.
Не могу понять
за проверку отвечает след код.
//получить email, которое ввёл пользователь
if (isset($_POST['email'])) {
$email = $_POST['email'];
if (!filter_var($email,FILTER_VALIDATE_EMAIL)) {
$data['email']='Invalid email.';
$data['result']='error';
}
} else {
$data['result']='error';
}
а также по какой то причине не показывает не показывает подпись об ошибке у поля.
Александр Мальцев
Александр Мальцев
Внёс много изменений в форму обратной связи.
Добавил проект на Github: github.com/itchief/feedback-form-with-recaptcha-2
Ссылка на архив: yadi.sk/d/jrEy-35W3LDYk4
Тестируйте…
Евгений
Евгений
Все ок. Куда вводить публичный ключ?))
Евгений
Евгений
… понял что в скрипте. Тестирую.
Евгений
Евгений
Александр, добрый день! Ваша форма работает отл. Но как именно в этой форме сделать модальное окно и размножить ее по разным страницам через кнопку отправить запрос, например. Спасибо!

Знаю что подобное делали с другой вашей формой, но как я понял они разные — формы, технология применения модального окна такая же?
Александр Мальцев
Александр Мальцев
Здравствуйте, спасибо.
Посмотрю, как это можно сделать. Когда получится, напишу.
Александр Мальцев
Александр Мальцев
Форма обратной связи с Google reCAPTCHA в модальном окне:
Если вы хотите одну форму использовать на нескольких страницах, то её можно поместить в отдельный файл, а затем на необходимых страницах проекта подключить этот файл с помощью php функции include. В этом случае — если потребуется изменить форму, то это нужно будет сделать всего в одном файле.
Если же вы не хотите это делать на сервере или увеличивать размер HTML файла, то можете поместить форму обратной связи опять же в отдельный файл, а затем подгружать её на страницу с помощью AJAX (например, посредством jQuery функции get или load).
nicross
nicross
Подскажите, пожалуйста.

В файле script.js заменил:

// эту строчку
var typeFile = 'image.*';
// на следующую
var typeFile = [
	'jpg',
	'jpeg',
	'png',
	'rar',
	'7z',
	'doc',
	'docx',
	'xls',
	'xlsx',
	'pdf',
];

//эту строчку
var maxSizeFile = 524288; //512 Кбайт
// на следующую
var maxSizeFile = 104857600; //100 Мбайт

// эту строчку
else if (!file.type.match(typeFile)) {
  $(this).next('p').text('* Файл не будет отправлен, т.к. его тип не соответствует разрешённому');
}
// на следующую	  
else if ($.inArray(file.name.split('.').pop().toLowerCase(),typeFile)==-1) {
  $(this).next('p').text('* Файл не будет отправлен, т.к. его тип не соответствует разрешённому');
}

// эту строчку
if ((file.type.match('image.*')) && (file.size<524288)) {
  formData.append('images[]', file, file.name);
}
// на следующую
if (($.inArray(file.name.split('.').pop().toLowerCase(),typeFile)>=0) && (file.size<104857600)) {
  formData.append('images[]', file, file.name);
}
В файле process.php заменил:
// эту строчку
$allowedExtension = array("jpg" => "image/jpg", "jpeg" => "image/jpeg", "gif" => "image/gif", "png" => "image/png");
// на следующую
$allowedExtension = array("jpg" => "", "jpeg" => "", "png" => "", "rar" => "", "7z" => "", "doc" => "", "docx" =>"", "xls" => "", "xlsx" => "", "pdf" => "");
  
// эту строчку
$maxSizeFile = 524288;
// на следующую
$maxSizeFile = 104857600;

// эту строчку
if (!array_key_exists($extFile, $allowedExtension)) {
// на следующую
if (!in_array($extFile, $allowedExtension)) {
При прикрепление файлов соответствующих расширений все норм, но при попытке отправить вылезает сообщение о ошибке

«Произошла ошибка при отправке формы на сервер.»
«Код капчи не прошёл проверку на сервере»

Александр Мальцев
Александр Мальцев
Вам необходимо проверить значение полученных вами ключей с сайта Google reCAPTCHA:
1. Публичного в строчке:
<div class="g-recaptcha" data-sitekey="значение_вашего_публичного_ключа"></div>
2. Секретного:
$secret = 'значение_вашего_секретного_ключа';
nicross
nicross
Александр, спасибо за оперативный ответ.
Ключи еще раз проверил, указаны правильно.

Но думаю, дело не в ключах, так как если не прикреплять файл, то отправка идет без ошибок.

Я использую форму с рекапчей во всплывающем окне. Может быть в этой форме есть какие-то другие нюансы?
Александр Мальцев
Александр Мальцев
Не знаю, не должно быть проблем. Если есть возможность, то предаставьте ссылку на ваш архив с формой.
nicross
nicross
Загрузил архив с сайта на яндекс диск . Только убрал секретный ключ и адрес почты в process.php
Александр Мальцев
Александр Мальцев
Поправил: yadi.sk/d/lgH4SGzA3Ks75q
nicross
nicross
Спасибо большое Александр. Все заработало!
Евгений
Евгений
Обновление закона. С 1 июля 2017 вступают в силу изменения в Кодексе об Административных Правонарушениях РФ. Персональные данные.
Получается в форме нужна галочка с заголовком-ссылкой "Я принимаю условия" если перейдет по ссылке то открывается окно шаблона текста о политике конфиденциальности.

Александр, добры день. Что-то подобное делали в своих формах?
Евгений
Евгений
Если быть точнее, кнопка отправить становится активной, когда поставили галочку.
Александр Мальцев
Александр Мальцев
Да, это делается очень просто.
1. Необходимо в форму добавить checkbox:
<div class="checkbox">
  <label>
    <input type="checkbox" name="agree"> Я принимаю <a href="#">условия</a>
  </label>
</div>
2. Добавить в JS следующий код:
$('input[name="agree"]').change(function(){
  if(this.checked) {
    $(this).closest('form').find('[type="submit"]').prop('disabled',false);
  } else {
    $(this).closest('form').find('[type="submit"]').prop('disabled',true);
  }
})
Форма, для отправки которой необходимо принять условия (поставить галочку): yadi.sk/d/cFNZXx0H3Keumj
Евгений
Евгений
Добрый день, Александр забыли указать (в архиве конечно все есть)

3. Добавить к кнопке отправить
disabled="disabled"
Спасибо!
Arkady347
Arkady347
Добрый день всем!
Прекрасная капча, прекрасно работает! Спасибо Александру!
Одно напрягает: после постановки галочки приходится еще разгадывать ребусы на 2-3 картинках, появляющихся одна за другой. Не хочется напрягать пользователя.
Видел на многих сайтах эту же капчу без всяких картинок, одна галочка и вперед! Настроение не портится. Может, кто-то подскажет как запретить появление этих картинок?
Александр Мальцев
Александр Мальцев
Это зависит от того, как сервис reCAPCTHA распознаёт действия пользователя (или того, кто пытается это сделать). Если они считаются подозрительными, то после нажатия на галочку, он предлагает решить капчу. А если нет, то происходит отправка формы. На других сайтах тоже будут появляться картинки, если вы будете отправлять некоторую форму несколько раз или использовать режим инкогнито в браузере.
Arkady347
Arkady347
Да, действительно я много раз тестил одну и ту же форму (больше 20), и каждый раз появлялись картинки, видимо, я был принят за робота. Спасибо вам!
Евгений
Евгений
Добрый день. Все круто с модулем.
Александр, подскажите как в этом модуле подключить автоматический ответ «клиенту на его указанные email» письмом с шаблонам типа «Спасибо за заказ с сайта… и наши контакты для связи».
Может конечно, где-то уже это реализовано у вас.
Было бы вообще здорово видеть такую фишку! с меня $
За ранее спасибо!
Александр Мальцев
Александр Мальцев
Добрый, Евгений!
Это действие осуществляется очень просто. Необходимо после отправки одного письма, вставить отправку ещё одного (клиенту).
if ($mail->Send()) {
  $data['result']='success';
} else {
  $data['result']='error';
}

// добавляем следующее:
$mail->ClearAllRecipients();
$mail->clearAttachments();
$mail->From = 'email@mysite.ru'; // от какого email
$mail->FromName  = 'Имя сайта'; // от какого имени
$mail->Subject = 'Спасибо за заказ с сайта…'; // тема письма
$mail->Body = $name . ', ваше сообщение доставлено. Наши контакты для связи...'; // тело письма
$mail->AddAddress($email); // адрес письма (берём из поля email)
// отправляем письмо
if ($mail->Send()) {
  $data['result']='success';
} else {
  $data['result']='error';
}
...
Евгений
Евгений
Александр,
Я так понимаю это правится только process.php

Постскриптум: Я вставил код и протестил, то мне на почту с сайта пришло 2 письма одинаковых, а клиенту ничего.

Привожу кусок нижнего когда с process.php Ваш код куда вставить надо?
//

.....

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      = 'Оставил пустым';
    $mail->FromName  = 'Запрос с ';
    $mail->Subject   = 'Сообщение с формы обратной связи';
    $mail->Body      = $output;
    $mail->AddAddress( Оставил пустым' );
    // прикрепляем файлы к письму
    if (isset($files)) {
      foreach ($files as $value) {
        $mail->addAttachment($value);
      }
    }

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

  }
  
  echo json_encode($data);

?>
Александр Мальцев
Александр Мальцев
Да, необходимо поправить только process.php.
Полный пример:
...
// 2. Отправляем на почту
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";
$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 (isset($files)) {
  foreach ($files as $value) {
    $mail->addAttachment($value);
  }
}
if ($mail->Send()) {
  $data['result']='success';
} else {
  $data['result']='error';
}
// второе письмо (клиенту)
$mail->ClearAllRecipients();
$mail->clearAttachments();
$mail->From = 'email@mysite.ru'; // от какого email (настраиваем)
$mail->FromName  = 'Имя сайта'; // от какого имени (настраиваем)
$mail->Subject = 'Спасибо за заказ с сайта…'; // тема письма (настраиваем)
$mail->Body = $name . ', ваше сообщение доставлено. Наши контакты для связи...'; // тело письма (настраиваем)
$mail->AddAddress($email); // кому (эту строчку не меняем)
// отправляем письмо
if ($mail->Send()) {
  $data['result']='success';
} else {
  $data['result']='error';
}


}
echo json_encode($data);
?>
Евгений
Евгений
Спасибо работает.
Было бы неплохо видеть небольшой шаблон в формате html со стандартной отправкой.
Александр Мальцев
Александр Мальцев
Отлично!
Чтобы использовать email шаблон, его нужно создать (например: yadi.sk/d/POIcqpXz3KA4LN). В необходимые места шаблона положить плейсхолдеры (%email.title%, %email.nameuser%, %email.message%), которые при формировании письма будут заменены значениями с формы.
Формирование письма и его отправку в файле process.php можно осуществить так:
// отправка почты
require_once dirname(__FILE__) . '/phpmailer/PHPMailerAutoload.php';
$bodyMail = file_get_contents('email.tpl'); // получаем содержимое email шаблона (настроить путь к нему, если он будет находиться в директории отличной от той, в которой находится process.php)
// выполняем замену плейсхолдеров реальными значениями
$bodyMail = str_replace('%email.title%', 'Сообщение с формы обратной связи',$bodyMail);
$bodyMail = str_replace('%email.nameuser%', $name, $bodyMail);
$bodyMail = str_replace('%email.message%', $message, $bodyMail);
$bodyMail = str_replace('%email.emailuser%', $email, $bodyMail);
$bodyMail = str_replace('%email.date%', date('d.m.Y H:i'), $bodyMail);

$mail = new PHPMailer; // создаём экземпляр класса PHPMailer
$mail->CharSet = 'UTF-8';
$mail->IsHTML(true);  // формат HTML
$mail->From      = 'email@mysite.ru';
$mail->FromName  = 'Имя сайта';
$mail->Subject   = 'Сообщение с формы обратной связи';
$mail->Body      = $bodyMail;
$mail->AddAddress( 'myemail@mail.ru' );
if (isset($files)) {
  foreach ($files as $value) {
    $mail->addAttachment($value);
  }
}
if ($mail->Send()) {
  $data['result']='success';
} else {
  $data['result']='error';
} 
Arkady347
Arkady347
Спасибо за ваш труд! Скачал вашу «готовую форму обратной связи с recaptcha», вставил свои коды, полученные у Гугла, в указанные файлы, вписал свой e-mail в файл process.php, загрузил всю папку на сайт: elenaturkka.ru/feedback/index.html

Но после заполнения всех полей формы ничего не происходит, кроме появления двух зеленых галочек в полях имя и емэйл, сообщение на емэйл так же не приходит :( Видимо, в «готовой капче» нужно доделывать что-то еще.

У меня стоит довольно примитивная форма на сайте, который сделал в свое время ( elenaturkka.ru/ord.php ), вторую неделю пытаюсь прикрутить к ней гугловскую рекапчу, прочел больше десятка статей с советами, как все это надо делать, пытался выполнять рекомендации, но так и не смог. Капча красивенько стоит, но свою функцию не выполняет. Трудно быть не программистом. Если не ответите, продолжу поиски…
Александр Мальцев
Александр Мальцев
У вас возникает ошибка на 182 строчке в файле process.php. Если не сможете её самостоятельно исправить, то приведите код данной строчки.
Arkady347
Arkady347
Господи, и как вам так сразу удалось распознать такую мелочь? Я заменил в этой строчке у емэйла, обрамленного одинарными кавычками, значок апострофа, очень на них похожий ( ' ), и все заработало. Ну спасибо, Профессор!!! Преклоняюсь…
Алексей
Алексей
Здравствуйте,
подскажите пожалуйста, как прикрутить к данной форме progress-bar от bootstrap на время загрузки файлов на сервер?

Александр Мальцев
Александр Мальцев
Добрый день.
Для этого необходимо:
1. В HTML форму добавить progress-bar (например, перед кнопкой submit):
<div class="clearfix"></div>
<div class="progress" style="display:none;">
  <div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
    <span class="sr-only">0%</span>
  </div>
</div>
<div class="clearfix"></div>
<!-- Кнопка, отправляющая форму по технологии AJAX -->            
<button name="send-message" type="submit" class="btn btn-primary pull-right">Отправить сообщение</button>
2. В файл script.js добавить дополнительный код в ajax функцию, а именно параметр xhr.
$.ajax({
  type: "POST",
  url: "/feedback/process.php",
  data: formData,
  contentType: false,
  processData: false,
  cache: false,
  beforeSend: function() {
    $('#messageForm .progress').show();
    $(':submit').prop('disabled', true);
  },
  xhr: function() {
    var myXhr = $.ajaxSettings.xhr();
    if(myXhr.upload){
      myXhr.upload.addEventListener('progress',function(event) {
        // если известно количество байт для пересылки
        if (event.lengthComputable){
          // получаем общее количество байт для пересылки
          var total = event.total;
          // получаем какое количество байт уже отправлено
          var loaded = event.loaded;
          // определяем процент отправленных данных на сервер
          var progress = ((loaded * 100)/total).toFixed(1);
          // обновляем состояние прогресс бара Bootstrap
          var progressBar = $('#messageForm .progress-bar');
          progressBar.attr('aria-valuenow',progress);
          progressBar.width(progress+'%');
          progressBar.find('span').text(progress+'%');
        } 
      }, false);
    }
    return myXhr;
  },
  success: function (data) {
    $('#messageForm .progress').hide();
    $(':submit').prop('disabled', false);
    var $data =  JSON.parse(data);
    ...
Можно также дополнительно добавить параметр beforeSend, который будет во время отправки формы на сервер, изменять состояние кнопки submit на не активное, а также отображать индикатор загрузки (по умолчанию скрыт). После прохождения ответа (параметр success) добавить также дополнительно ещё 2 строчки, выполняющие обратное действие (возвращающее эти элементы в первоначальное состояние).
Алексей
Алексей
Огромное спасибо за помощь, Все работает как надо.
Евгений
Евгений
Александр, Здравствуйте. Для добавления doc, dox, pdf во вложение, как я понял нужно 2 изменения.

В process.php добавил следующее
$allowedExtension = array(«jpg» => «image/jpg», «jpeg» => «image/jpeg», «gif» => «image/gif», «png» => «image/png», «doc» => «doc», «docx» => «docx», «pdf» => «pdf»); // разрешённые типы файлов

Есть парочка вопросов
1. Нужно ли в этом коде перед doc, dox, pdf указывать «image/...»?
2. Что нужно вставить в script.js, чтоб заработали doc, dox, pdf

Огромное спасибо!
Александр Мальцев
Александр Мальцев
Здравствуйте.
В текущей версии неважно, что указывать в качестве значения ключа, т.к. сравнение идёт именно по ключу.
Т.е. можно так:
$allowedExtension = array("jpg" => "", "jpeg" => "", "gif" => "", "png" => "", "doc" => "", "docx" =>"", "pdf" => "");
Ответ на второй вопрос можешь посмотреть в этом комментарии: itchief.ru/lessons/php/how-to-install-recaptcha-on-website#comment-3861
В нём описано, как это сделать не только для js, но и для php.
Евгений
Евгений
Александр, здравствуйте.
Все получилось, работает.
1. Подскажите как прикрутить кнопку «ответить» когда приходит письмо на почту?
2. И как установить email отправителя, который он указывает при отправке, сейчас по умолчанию email@mysite.ru в коде.

Спасибо!
Александр Мальцев
Александр Мальцев
Здравствуйте.
Формируйте тело письма для отправки в формате HTML:
$mail->IsHTML(true);
$mail->Body = $output;
Добавить кнопку ответить можно так:
$output .= '<a href="mailto:email@mysite.ru">Ответить</a>';
Email отправителя устанавливается посредством изменения следующей строчки:
$mail->From = 'email@mysite.ru';
Андрей
Андрей
Здравствуйте, подскажите как обновить капчу после правильной отправки формы?
сделал форму под наши требования, после отправки она не скрывается, поля очищаются и можно отправить форму снова, только капча остается не обновленная, стоит галочка
Александр Мальцев
Александр Мальцев
Добавьте в JavaScript после успешного ответа (результат success) сброс капчи:
if ($data.result == "success") {
  grecaptcha.reset();
  ...
Андрей
Андрей
спасибо, подскажите как добавить возможность прикрепления файлов формата pdf, dwg? нашел уже в коментариях другой ваш пример feedback-form-image-and-archive, сделал как там, все равно не получается, приходят только картинки, когда прикрепляю пдф или другой файл, пусто
Александр Мальцев
Александр Мальцев
Попробуйте в JavaScript и PHP найти код, который отвечает за проверку расширений файлов и отключить (закомментировать) его. После этого (т.е. когда будет всё правильно работать) настроить его, чтобы он пропускал только необходимые файлы.
Алексей
Алексей
Здравствуйте. А подскажите как поправить форму чтобы она не грузила файлы на сервер. А отправляла сразу на почту.?
Александр Мальцев
Александр Мальцев
В файле process.php удалите строчки с 110 до 119 и 121.
На 120 строчке замените $files[] = $newFullFileName; на
$files[] = $tmpFile;
Алексей
Алексей
Спасибо Александр, заменил и удалил. Но файл приходит без расширения.
Вот как выглядит измененй код
// проверить расширение файла, размер файла и mime-тип
if (!in_array($extFile, $allowedExtension)) {
$data['files']='Ошибка при загрузке файлов (неверное расширение).';
$data['result']='error';
} elseif ($sizefile > $maxSizeFile) {
$data['files']='Ошибка при загрузке файлов (размер превышает 3МБ).';
$data['result']='error';
} else {
//ошибок не возникло, продолжаем…
// временное имя, с которым принятый файл был сохранён на сервере
$tmpFile = $_FILES['images']['tmp_name'][$key];

$files[] = $tmpFile;

}
} else {
//ошибка при загрузке файл на сервер
$data['result']='error';
}
Александр Мальцев
Александр Мальцев
Всё правильно, имя файла будет таким, которое даёт ему веб-сервер.
Можно оставить всё как было, и просто добавить код для удаления файлов на сервере после отправки письма:
if (isset($files)) {
  foreach ($files as $value) {
    unlink ($value);
  }
}  
Алексей
Алексей
То есть сервер не сохраняет расширение файлов?
А код удаления ставить после 121 строки?
Александр Мальцев
Александр Мальцев
Сервер сохраняет файл под уникальным именем. Информацию об этом файле можно получить из массива $_FILE.
Нет в самом конце после 195 строчки (когда письмо уже отправлено).
Александр
Александр
Александр, приветствую.
Гугл снова нас всех порадовал и сделал Invisible reCAPTCHA Сайт

В свете этого вопрос, а как заменить reCAPTCHA на Invisible reCAPTCHA?
Александр Мальцев
Александр Мальцев
Здравствуйте, Александр. Это тема уже отдельной статьи…
Александр
Александр
Буду с нетерпением ждать
Александр Мальцев
Александр Мальцев
Статья, в которой рассмотрены различные примеры по внедрению invisible reCAPTCHA в формы обратной связи: itchief.ru/lessons/php/website-protection-using-recaptcha-invisible
Представлены инструкции как это сделать для форм, работающих по AJAX, так и без неё. А также шаги по подключению нескольких invisible reCAPTCHA к одной странице.
Николай
Николай
Добрый день. А как в поле $mail->Body = $name. ', ваше сообщение в… доставлено!

На данное письмо отвечать не нужно.';

добавить html-код страницы красиво оформленного e-mail? Я вставляю код, но при отправке с сайта письма скрипт показывает ошибку и письмо не отправляет?
Александр Мальцев
Александр Мальцев
Здравствуйте. Вам необходимо указать, что тело письма является HTML. Как это сделать можете почитать здесь: itchief.ru/lessons/php/how-to-install-recaptcha-on-website#comment-3876

Удобнее будет не сразу присваивать длинную строку $mail->Body, а собрать её из кусочков, как это сделано в process.php.
$output = "...";
// добавляем к текущей строке ещё строку
$output .= "...";
// добавляем к текущей строке ещё строку и т.д.
$output .= "...";

// передаём полученную строку 
$mail->Body = $output;
Alisher
Alisher
Добрый день.
У меня ошибка: Код капчи не прошёл проверку на сервере

Alisher
Alisher
Спс решил )
Михаил
Михаил
Александр, добрый день.
Огромное спасибо за отличную форму и Вашу отзывчивость на наши приставания с вопросами.
Вопрос в следующем. Если не ставить галку «Я не Робот» (некоторые неискушенные пользователи интернета почему-то не обращают внимания на эту Гугловскую recaptchу) форма не отправляется (вообще ничего не происходит) и сообщения «Вы не прошли проверку „Я не Робот“ не появляется (многие на этом прекращают попытки и пишут на почту „Ваша форма не работает“).
Все перепроверял и сравнивал с исходниками неоднократно.
В чем может быть проблема.
И еще вопрос. Можно ли сделать так, что бы сообщениям присваивался номер (типа „Заказ#0001“, Заказ#0002» и т.д)?
Александр Мальцев
Александр Мальцев
Здравствуйте, Михаил. Да, в форме нет элемента, в который выводится эта ошибка.
Добавьте в форму следующий элемент:
<div id="recaptchaError" class="text-danger"></div>
Сообщения, например, можно сохранять в базу и получать номер заказа уже от туда.
Но, если нужно очень просто, то можно сделать так.
Создать дополнительный текстовый файл, например, orders.txt.
В файле process.php написать небольшой скрипт, например перед отправкой формы на почту:
// Сохранение номера заказа в файл:
// номер заказ == номер строки в файле
$numberOrder = count(file(dirname(__FILE__).'/orders.txt')) + 1;
$output = "Заказ N " . $numberOrder . "\n";
if (file_put_contents(dirname(__FILE__).'/orders.txt', $output, FILE_APPEND | LOCK_EX)) {
  $data['result']='success';
  // добавляем номер строки в data, чтобы вывести его пользователю
  $data['order'] = $numberOrder;
} else {
  $data['result']='error';
}
В форме немного изменяем сообщение:
<!-- Сообщение, отображаемое в случае успешной отправки данных -->
<div class="alert alert-success hidden" role="alert" id="msgSubmit">
  <strong>Внимание!</strong> Ваш заказ №<span id="order"></span> принят.
</div>
А также сценарий JavaScript:
if ($data.result == "success") {
  $('#messageForm').hide();
  // добавляем эту строчку:  
  $('#order').text($data['order']);
  $('#msgSubmit').removeClass('hidden');
Михаил
Михаил
Александр, добрый день.
Огромное спасибо. Все просто отлично. Фомой доволен выше крыши.
Но есть одно но. С некоторых устройств форма не отправляется.
Выяснить удалось через Вебвизор Яндекс-Метрики.
Форма заполняется, по движению мыши видно, что ставят галочку recaptchу, «заказать» и все, дальше ничего не происходит, видно, что тыкают мышкой во все подряд, и тишина.
К сожалению, посредством Вебвизора не выяснить, какие сообщения об ошибках при этом высвечиваются на ихнем мониторе.
Встречается на разных устройствах, но больше всего с windows 10, браузеры и chrom и firefox.
В чем может быть причина.
С одним человеком удалось связаться по телефону. Попросил его посмотреть код в chrom-е. Сказал, что высвечивает json. больше добиться от неё ничего не удалось.
Но на подавляющем большинстве устройств (компы, планшеты, смартфоны) форма работает отлично — присваивается номер заказа, отправляется копия письма на почту, прикрепляются файлы.
В чем может быть причина?
Александр Мальцев
Александр Мальцев
Здравствуйте, Михаил. Причин может быть несколько. Одна из причин может быть связана с тем, что пользователи, которые заполняют эту форму, используют старые версии браузеров. Например, браузеры, которые не поддерживает технологию XMLHttpRequest Level 2. Это Chrome версии ниже 7 и Firefox версии ниже 3.5. Но, ситуация с Windows 10 выглядит в этом случае как-то странно… Другая причина может быть связана с тем, что у пользователя отключён в браузере JavaScript. Хоть это обычно очень маленький процент, но он всё же существует. Эти все параметры можно проследить в Яндекс метрики.
Другая ситуация — может быть связана с тем, что пользователь использует старую версию файла скрипта (если у вас настроено кэширование, например в конфигурационном файле .htaaccess). Т.е. пользователь открыл страницу с формой обратной связи, при открытии страницы файлы, в том числе и script.js, попали в кэш. Потом вы его обновили на сервере, но при открытии страницы браузер пользователя не будет загружать новую версию файла, а будет использовать сохранённую (старую) версию. Может быть причина в этом. В этом случае можно переименовать файл script.js, например в script-v1.1.js и подключить его к странице.
Михаил
Михаил
Скорее всего на этом компе был отключен Javascript.
Можно ли сделать подсказку типа «У Вас отключен „Javascript“. Корректная работа формы невозможна».
Хотя, как это сделать, если этот Javascript отключен?
Александр Мальцев
Александр Мальцев
Почему нельзя. Для этого можно воспользоваться элементом noscript и поместить в него необходимое содержимое. Если в браузере не включен JavaScript, то браузер отобразит его содержимое. А если JavaScript включен, то нет.
Например, его можно расположить перед формой обратной связи:
...
<noscript>
  <p class="alert alert-danger">Уважаемый пользователь! У вас отключён JavaScript.
Корректная работа формы невозможна.</p>			
</noscript>
<!-- Форма обратной связи -->
<form id="messageForm" enctype="multipart/form-data">
...
Вячеслав
Вячеслав
Александр, снова добрый день, появился еще один вопрос. Не работают два поля («имя» и «email») в Safari на iPad. Поле textarea доступно для ввода, а эти нет. С мобильного телефона все получается, со сторонних браузеров на планшете тоже, что-то именно с Сафари. Проблема проявляется в том числе в демо, которую Вы публиковали на сайте. Пытался побороть своими силами, но сообразить не выходит, поля начинают работать лишь при условии удаления класса «form-group has-feedback» у textarea — однако в этом случае textarea в случае ошибки не окрашивается в красный и не имеет красного «х», выглядит некрасиво. Не дадите совет, как лучше поступить, что где удалить/прописать?
Вячеслав
Вячеслав
Стоило только задать вопрос, проблема сразу решилась удалением класса «has-feedback» у контейнера, в котором находится textarea. Теперь работают и окрашиваются все три поля (в том числе в Сафари на планшете), а также проставляются галочки/крестики в полях «имя» и «email», как и нужно.
Вячеслав
Вячеслав
Александр, добрый день! Большое спасибо за форму, установил, всё работает. Подскажите, пожалуйста, можно ли как-то «облегчить» код, удалив из bootstrap.min.css лишние классы, не фигурирующие (вроде бы) в форме? К примеру, .audio, .jumbotron и т.п. Не повлияет ли это на работоспособность формы? Особенно интересуют строки, в которых упоминается шрифт «glyphicon», зачем он нужен? Спасибо!
Александр Мальцев
Александр Мальцев
Добрый день! Шрифт необходим для отображения иконок в полях, которые будут отображаться, если к форме добавить атрибут novalidate.
Да, если вам дополнительные стили bootstrap.min.css не нужны, то можете их удалить. Они необходимы только для оформления формы и на её работоспособность никак не влияют. При необходимости данный файл вообще можно убрать и оформить форму с помощью своих стилей.
Наиболее просто убрать из файла bootstrap.min.css лишнее, можно на странице getbootstrap.com/customize/. Поставьте галочки только на нужных компонентах (например, Grid system, Form, Button) и получите файл bootstrap.min.css состоящий только из этих классов.
Вячеслав
Вячеслав
Благодарю, все понятно!
Николай
Николай
Теперь даже jpg не отправляет и то же самое выводит:

Александр Мальцев
Александр Мальцев
Из файла process.php необходимо ещё удалить этот код:
elseif (!in_array($filetype, $allowedExtension)){
  $data['files']='Ошибка при загрузке файлов (неверный тип файла).';
  $data['result']='error';
}
В итоге должно получиться следующее: yadi.sk/d/BUSIKJTi3BeR5k
Николай
Николай
К сожалению, после загрузки файла пишет — «Произошла ошибка при отправке формы на сервер. Ошибка при загрузке файлов (неверный тип файла).» Загружал файл объемом 18Мб и расширением mp4.

Я в строку
var typeFile = [
  'jpg',
  'jpeg',
  'gif',
  'png',
  'avi',
  'mkv',
];
добавил еще 'mp4'. И в строку
$allowedExtension = array("jpg", "jpeg", "gif", "png", "rar", "7z", "zip");
— тоже.
Николай
Николай
Установил именно эту форму. Скажите, что поменять, чтобы файлы отправлялись в папку files, а на почту приходила только ссылка для скачивания. И чтобы можно было прикреплять кроме изображений видео до 100 Мб. На хостинге разрешение до 100 Мб установил уже. Спасибо!
Александр Мальцев
Александр Мальцев
Для этого необходимо внести изменения в файл script.js (на стороне клиента, т.е. в браузере) и process.php (на сервере).
В файле script.js необходимо изменить следующие строки:
// эту строчку
var typeFile = 'image.*';
// на следующую
var typeFile = [
  'jpg',
  'jpeg',
  'gif',
  'png',
  'avi',
  'mkv',
];

//эту строчку
var maxSizeFile = 524288; //512 Кбайт
// на следующую
var maxSizeFile = 104857600; //100 Мбайт

// эту строчку
else if (!file.type.match(typeFile)) {
  $(this).next('p').text('* Файл не будет отправлен, т.к. его тип не соответствует разрешённому');
}
// на следующую	  
else if ($.inArray(file.name.split('.').pop().toLowerCase(),typeFile)==-1) {
  $(this).next('p').text('* Файл не будет отправлен, т.к. его тип не соответствует разрешённому');
}

// эту строчку
if ((file.type.match('image.*')) && (file.size<524288)) {
  formData.append('images[]', file, file.name);
}
// на следующую
if (($.inArray(file.name.split('.').pop().toLowerCase(),typeFile)>=0) && (file.size<104857600)) {
  formData.append('images[]', file, file.name);
}
В файле process.php:
// эту строчку
$allowedExtension = array("jpg" => "image/jpg", "jpeg" => "image/jpeg", "gif" => "image/gif", "png" => "image/png");
// на следующую
$allowedExtension = array("jpg", "jpeg", "gif", "png", "rar", "7z", "zip");
  
// эту строчку
$maxSizeFile = 524288;
// на следующую
$maxSizeFile = 104857600;

// эту строчку
if (!array_key_exists($extFile, $allowedExtension)) {
// на следующую
if (!in_array($extFile, $allowedExtension)) {
Для того, чтобы в письме файлы приходили в виде ссылок необходимо выполнить следующее:
1. Удалить из файла process.php следующий код:
// прикрепляем файлы к письму
if (isset($files)) {
  foreach ($files as $value) {
    $mail->addAttachment($value);
  }
}
2. Добавить в то место где формируем тело письма этот код:
if (isset($files)) {
  $output .= "Файлы: " . "\n";
  foreach ($files as $value) {
    $href = substr($value,strpos($value, '/feedback/'));
    $output .= '<p><a href="'.$href.'">'.$href.'</a></p>' . "\n";
  }
}
Николай
Николай
В письме приходит вот такого вида ссылка:
Файлы: 
<p>
  <a href="/feedback/files/img_588e012d756cf4.81264327.jpg">
    /feedback/files/img_588e012d756cf4.81264327.jpg
  </a>
</p>
Видимо, потому что письмо не HTML. Тогда как сделать, чтобы ссылка приходила готовая:
http://сайт.ру/feedback/files/название файла.расширение файла
Александр Мальцев
Александр Мальцев
Для этого необходимо добавить перед $mail->Body = $output; строчку:
$mail->IsHTML(true);
Дмитрий007
Дмитрий007
Здравствуйте, форма работает, проверка полей работает практически корректно (количество символов не проверяет, точнее достаточно одну букву написать и он ругаться не будет, хотя ограничение стоит минимум 20 символов), капча работает, но вот когда нажимаешь отправить ничего не происходит, показывает как буд-то все нормально, но не отправляется письмо. В чем может быть проблема?
Александр Мальцев
Александр Мальцев
Здравствуйте. Проверка полей формы осуществляется функцией checkValidity. Возможно, браузер, в котором вы проверяете форму, не поддерживает данную функцию или в её поддержке имеются какие-то ограничения. На текущий момент поддержка этого API реализовано в 97.27% используемых браузерах. Проверить, поддержку этой функции можно на странице caniuse.com/#search=checkValidity. При желании конечно можно реализовать проверку полей с помощью какого-нибудь плагина jQuery или написать код JavaScript самому. Но в любом случае проверку полей формы на клиенте можно обойти и поэтому использовать какие-то дополнительные плагины или увеличивать код JavaScript не вижу смысла. Хотя решать вам…

Если письмо не отправляется, то значит, происходит какая-то ошибка на сервере. Для начала попробуйте проверить поддерживает ли хостинг вообще отправку писем. Или то, что вы используете… Также посмотрите, какой вообще AJAX ответ приходит с сервера на ваш запрос. Для этого можно воспользоваться вкладкой Network в панели разработчика браузера.
Дмитрий
Дмитрий
Александр, добрый день.
Существуют ли какие-либо «подводные камни» при установке recaptcha взамен ранее использовавшейся? Попытались решить вопрос с заменой капчи «наскоком» получили форму, которая отправляет сообщение независимо от результата обработки recaptcha.

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

Заранее спасибо.

С уважением,
Дмитрий
Александр Мальцев
Александр Мальцев
Здравствуйте, Дмитрий.
Наверно что-то не так настроили. reCaptcha — это надёжная капча и проблем с обработкой её результатов не должно быть.
Артем
Артем
Добрый вечер!
Подскажите пожалуйста, скачал вашу форму обратной связи с reCaptcha и установил на Denwere, все вроде хорошо, но при отправке сообщения вываливается ошибка VM34651:1 Uncaught SyntaxError: Unexpected token < in JSON at position 0(…)success @ script.js:143i @ jquery-1.12.4.min.js:2fireWith @ jquery-1.12.4.min.js:2y @ jquery-1.12.4.min.js:4c @ jquery-1.12.4.min.js:4
Ругается вот на это: var $data = JSON.parse(data);
Код не менял, подскажите пожалуйста что сделать? Возможно это Denwer глючит?
Александр Мальцев
Александр Мальцев
Здравствуйте, Артем.
Такая ошибка говорит о том, что в процессе выполнения файла process.php возникает какая-то ошибка. Это приводит к тому, что не выполняется эта строчка:
echo json_encode($data);
Т.е. мы не получаем ответ в формате json.
А JavaScript пытается разобрать то, что не является json. Поэтому он и «ругается» на эту строчку (var $data = JSON.parse(data)).
Вам необходимо посмотреть, какая возникает ошибка. Это можно, например, увидеть во вкладке Network панели разработчика браузера.

Надо пробовать на реальном сайте. В Denwer форма может не работать.
Артем
Артем
Спасибо за ответ, но, к сожалению все равно не работает. Запустил на хостинге.
Вот, что говорит хром:
Request URL:http://1.u0154129.z8.ru/process.php
Status Code:500 Internal Server Error
Изображения:
itchief.ru/assets/uploadify/8/0/b/80b191b7ec82fb0d35c41f76bb41aec7.jpg
itchief.ru/assets/uploadify/3/e/2/3e2b558993f30b3a495a57ec5bd08497.jpg
itchief.ru/assets/uploadify/1/7/8/178ab8ba94b39c8842c0353a32a5de18.jpg

В php я «валенок». Если окажите помощь, буду вам очень благодарен.
Александр Мальцев
Александр Мальцев
По умолчанию эту форму необходимо поместить в каталог feedback на сервере или правильно настроить пути. Также стоит обратить внимание на версию php. Для работы php библиотеки Google reCapctha необходим php >= 5.3.2, а у вас установлен 5.2.17. При возникновении ошибки 500, желательно читать информацию из файла, в который записывает лог ошибок сервера.
Артем
Артем
Спасибо большое.
Артем
Артем
Александр, спасибо Вам, все заработало.
Есть к Вам просьба, добавить несколько полей для заполнения в форму. Пробовал сделать сам, но не получилось, (выдает ошибку отправки формы на сервер)
Если Вам не сложно помогите пожалуйста, нужны следующие поля: Имя, маил, №тел, Название организации, Тема, сообщение.

Зарание спасибо.
Александр Мальцев
Александр Мальцев
Этот момент уже обсуждался не раз, наиболее просто это сделать так:
1. Открыть файл script.js, найти в нём строчку
$.ajax({
и добавить перед ней необходимые поля в объект formData следующим образом:
formData.append('имя_поля', $("#id_поля").val());
'имя_поля' — это некоторое имя, которое затем на сервере можно будет получить так:
$_POST['имя_поля']
2. В файле process.php добавить переданные значения в тело письма (но при этом необходимо проверить, есть ли в массиве $_POST указанное имя):
$output .= "Сообщение: " . $message . "\n";
// дублируем этот блок столько раз, сколько необходимо полей добавить к телу письма
if (isset($_POST['имя_поля'])) {
  $output .= "Имя_поля: " . $_POST['имя_поля'] . "\n";
}
Георгий
Георгий
Здравствуйте! У Вас не найдется всплывающей формы без капчи и только двумя полями для заполнения «имя» и «телефон»? Нужно для обратного звонка. Буду очень благодарен!
Александр Мальцев
Александр Мальцев
Форма для обратного звонка: yadi.sk/d/unjPnijlyPuJV
Александр
Александр
Сейчас оно вот в таком виде
По кнопкам Заказа звонка и Запроса замеров вроде отрабатывает, по 4м кнопкам хочу, письмо отправляется, форма не прячется, сообщения о отправке не выдается в консоль выводится:
true
1209
Uncaught SyntaxError: Unexpected token < in JSON at position 1(…)
Ошибка синтаксиса ссылается на строку var $data = JSON.parse(data); файла formcheck.js
Александр Мальцев
Александр Мальцев
Это ошибка означает то, что сервер возвращает результат не соответствующий формату JSON.
Попробуйте проанализировать ответ, который приходит с сервера на вкладке браузера Network в панели разработчика. Может вы используете на стороне сервера некоторые поля, которые не указали в форме или что-то другое. Попробуйте проверить каждую форму по отдельности на предмет ошибок.
Александр
Александр
Вот что в консоли во вкладке Network про файл process.php

Warning: session_start(): Cannot send session cookie — headers already sent by (output started at… /process.php:1) in… /process.php on line 3

Warning: session_start(): Cannot send session cache limiter — headers already sent (output started at… /process.php:1) in… /process.php on line 3
{«result»:«success»}

Но для меня это птичий язык...(
Александр
Александр
Проверял по отдельности, каждая форма в отдельном html, результат тотже. что вместе, что по отдельности, косяк только с обработкой формы которая по кнопкам Хочу и в которую javascript-ом пишутся options в select
Александр
Александр
Нашел.
Как оказалось файл process.php начинался с: " <?php", — (/пробел/<?php)
В жизни не подумал бы, что из-за этого…
Александр
Александр
Вроде все работает,
Но странно ведет себя форма запроса звонка, непредсказуемо через раз, через два отправляется, когда не отправляется жалуется на то, что серверу пришло пустое поле name:
{result: «error», name: «Поле имя не должно быть пустым.»}
name
:
«Поле имя не должно быть пустым.»
result
:
«error»

Я в файле php проверку длины поменял на проверку непустое:
//получить имя, которое ввёл пользователь
if (isset($_POST['name'])) {
$name = $_POST['name'];
if (empty($name)) {
$data['name']='Поле имя не должно быть пустым.';
$data['result']='error';
}
} else {
$data['result']='error';
}

в js ничего не менялось.

Поле:
input type=«text» class=«form-control» id=«name» name=«name» required=«required» value="" placeholder=«Алексей Сергеевич Петров» minlength=«4» style=«border: 1px solid rgba(153, 153, 255, 0.5);width:100%;»

Где может быть засада?
причем на остальных формах с полем name я поступил точно также и они работают
Александр Мальцев
Александр Мальцев
Попробуйте, поискать ещё ошибки…
Александр
Александр
И еще вопрос появился, после того, как заработала форма про «Хочу», кнопок «Хочу» — 4 штуки, если 1 раз форма отработала, а пользователь, например хочет еще другое «Хочу», то во второй и следующие разы открывается модальное окно в котором форма скрыта, но отображается сообщение об успешной отправке первого запроса. Как быть с этим.
Александр Мальцев
Александр Мальцев
Необходимо переделать алгоритм в JavaScript так, чтобы он не скрывал форму, а очищал все заполненные поля для возможности повторной отправки формы. А также чтобы он отображал сообщение об успешной отправки, например, с помощью плагина jGrowl.
Александр
Александр
Подскажете, как это сделать? А-то я уже боюсь трогать, по принципу не навредить, а учитывая, что я чайник, навредить — это я запросто.
Александр
Александр
Нашел вот такой уведомитель bootstrap-notify.remabledesigns.com, но как его прикрутить не знаю.
То есть мысль ясна: получить ответ от сервера, если все хорошо; очистить поля формы; форму (модальное окно) закрыть, всплывающее уведомление показать.
А вот как это сделать?
Александр
Александр
Александр, приветствую.

Подключил bootstrap-notify в локалке на тестовых страничках — работает как надо,
Когда подключаю его к сайту на joomla происходит следующее:
1. bootstrap-notify требует для работы bootstrap.js (он же нужен, чтобы модальное окно программно закрывать по .modal('hide'))
2. после подключения bootstrap.js к живому joomla сайту модальные окна сами закрываются едва открывшись.
в чем может быть проблема?
Александр Мальцев
Александр Мальцев
Если использовать jGrowl, то это будет осуществляться следующим образом:
1. Скачать и подключить к странице плагин jGrowl:
<!-- подключить файл стилей CSS jGrowl -->
<link rel="stylesheet" href="/feedback/css/jquery.jgrowl.min.css">
<!-- добавить темы сообщений -->
<style>
  .message-success {
    background-color: green !important;
  }
  .message-error {
    background-color: brown !important;
  }
  .message-info {
    background-color: black !important;
  }
</style>
<!-- подключить скрипт jGrowl -->
<script src="/feedback/js/jquery.jgrowl.min.js"></script>
2. Изменить параметры success и error метода jQuery ajax:
success: function(data) {
  // разбираем строку JSON, полученную от сервера
  var $data = JSON.parse(data);
  // если сервер вернул ответ success, то значит двнные отправлены
  if ($data.result == "success") {
    // сбрасываем виджет reCaptcha
    grecaptcha.reset();
    // очистить форму
    $('#messageForm').find('input,textarea').each(function() {
      $(this).val('');
      $(this).parents('.form-group')
               .removeClass('has-success has-error')
             .find('.form-control-feedback')
               .removeClass('glyphicon-ok glyphicon-remove');
    });
    // очистить файлы
    $('#upload-files').html('<input type="file" name="images[]"><p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>');
    // вывести сообщение об успешной отправки
    $.jGrowl("Внимание!
Ваше сообщение успешно отправлено.", { life: 10000, theme: 'message-success' });
  } else {
    // вывести сообщение об ошибке
    $.jGrowl("Внимание!
Произошла ошибка при отправке формы на сервер.", { life: 10000, theme: 'message-error' });
    // сбрасываем виджет reCaptcha
    grecaptcha.reset();
    // выводим ошибки о невалидности полей формы
    if ($data.name) {
      $.jGrowl($data.name, { life: 10000, theme: 'message-error' });
    }
    if ($data.email) {
      $.jGrowl($data.email, { life: 10000, theme: 'message-error' });
    }
    if ($data.message) {
      $.jGrowl($data.message, { life: 10000, theme: 'message-error' });
    }
    // Если существует свойство msg у объекта $data, то...
    if ($data.msg) {
      // вывести сообщение об ошибке кода капчи
      $.jGrowl($data.msg, { life: 10000, theme: 'message-error' });
    }
    if ($data.files) {
      // вывести сообщение об ошибке, которая произошла при загрузке файлов
      $.jGrowl($data.files, { life: 10000, theme: 'message-error' });
    }
  }
},
error: function(request) {
  // вывести сообщение о том что произошла ошибка во время отправки данных
  $.jGrowl('Произошла ошибка ' + request.responseText + ' при отправке данных.', { life: 10000, theme: 'message-error' });
}
Готовый пример можно получить по ссылке: yadi.sk/d/IS2h3L4IyPK8w
Александр Мальцев
Александр Мальцев
Не знаю, он мне как-то не приглянулся. Выше привёл пример с использованием jGrowl.
Александр
Александр
Таки как оказалось jGrowl-у тоже нужен bootstrap.js, как минимум чтобы программно закрыть модальное окно через $('feedbackForm').modal('hide'), и плюсом к тому без него не работает конструкция $.jGrowl…
Александр
Александр
Александр, приветствую.

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

Можете помочь, — посмотреть, Может свяжемся по электронной почте.
Александр
Александр
Почему сообщение не выводилось — разобрался.
А вот почему две другие формы не отправляются не понимаю… (

Где-то накосячил в js и php обрабтчиках

Ссылка на zip архив
форма обратного звонка — отрабатывает
Остальные две — затыкаются после нажатия на кнопку отправки
Александр Мальцев
Александр Мальцев
Здравствуйте, Александр.
Комментарий на эту тему:
itchief.ru/lessons/php/how-to-install-recaptcha-on-website#comment-2852
Ответ с виджета, если их несколько, необходимо получать по его идентификатору.
Если виджеты, например, имеют идентификаторы recaptcha1 и recaptcha2, то и отправлять их ответ на сервер необходимо по id:
var captcha = grecaptcha.getResponse(recaptcha1);
// добавить в formData значение recapcha1
formData.append('g-recaptcha-response', captcha);
Александр
Александр
Александр, благодарю, за науку.
В локале работает. буду пробовать на живом.
Александр
Александр
Александр еще вопрос по путям к скриптам.
Допустим все 6 скриптов проверки и обработки (3js+3php) мы положили в корень сайта.
Подключая их на страницах src формируем через «location.origin + '/formcheck.js';».
Это работает, пути в src тегов script прописываются.
В этих js скриптах проверки форм, пытаюсь проделать тот-же фокус с путем к php, например:


// Формируем путь к скрипту
var ofcURLPHP = CurrentDomain + "/process.php";
// технология AJAX
$.ajax({
//метод передачи запроса — POST
type: «POST»,
//URL-адрес запроса
url: ofcURLPHP,
//передаваемые данные — formData
data: formData,


И вот тут похоже, что в url: не пишется путь до скрипта, по нажатию на кнопку отправки формы, форма не отправляется и модальное окно закрывается.
Можно как-то это вылечить?
(Смысл задачи в том, чтобы на внутренних страницах сайта, имеющих, например путь site.ru/product/okno/okna.html не прописывать руками пути к скриптам обработчикам, не множить их в подпапках).
Александр
Александр
С этим разобрался, не подключались JS хоть пути и прописывались.
Все работает, только 1 форма начала вести себя, как во вчерашнем вопросе (не отсылается по нажатию кнопки)…
После исправлений по вчерашней вашей рекомендации все работало.
И в принципе в js только добавилось определение адреса, где php лежит.
Cсылка на архив
Форма про типовые.
Александр
Александр
Которая по кнопке «Хочу» открывается.
Александр Мальцев
Александр Мальцев
Проверьте значения переменной formValid и капчи перед if. Так как после проверки данные дальше уже идут на отправку.
console.log(formValid);
console.log(captcha.length);
if ((formValid) && (captcha.length)) {
При сбросе reCaptcha также необходимо указывать идентификатор:
grecaptcha.reset(recaptcha1);
Александр
Александр
В консоли 2 строчки:
true
953.

Но самое странное не это.
Форма, которая по кнопкам «Хочу» заработала просто сама по-себе, но заболела форма про «перезвоните мне»
Александр
Александр
А в каком именно месте надо сбрасывать recaptcha??
Александр
Александр
Ага. нашел, где сбрасывается рекапча.

Проставил идентификаторы.
Та форма, что по кнопкам «Хочу» — работать перестала, за-то вылечилась форма запроса звонка.
Александр
Александр
Убрал везде идентификаторы, все заработало. само по себе, все три формы.
Волшебство какое-то.
Александр
Александр
А сегодня не работает, и не понятно почему.
Александр, может мы сможем это поправить возможно не безвозмездно.
Аноним
Аноним
Здравствуйте!
У меня такой вопрос, возможно ли уведомлять юзера, что файл был принят/загружен, а то ошибки выдаются типа: (Файл не будет загружен, размер больше 512Кбайт), а по успеху тишина.
Буду оч благодарен за помощь. Сам я 2-а по кушу в этом = )
PS Форма у меня с обычной каптчей взятая тут: itchief.ru/lessons/php/feedback-form-for-website

Поздно увидел с каптчей от гугла… переделывать не охота = )
Александр Мальцев
Александр Мальцев
Здравствуйте.
Тут нет ничего сложно.
Необходимо открыть файл script.js и изменить внутреннее содержимое блока
if (e.target.files.length>0) {
  //...
}
на следующее:
var file = e.target.files[0];
if (file.size>maxSizeFile) {
  $(this).next('p').text('* Файл не будет отправлен, т.к. его размер больше 512Кбайт');
  $(this).next('p').css('color','red');
}
else if (!file.type.match(typeFile)) {
  $(this).next('p').text('* Файл не будет отправлен, т.к. его тип не соответствует разрешённому');
  $(this).next('p').css('color','red');
}
else if ((file.size<=maxSizeFile) && (file.type.match(typeFile))) {
  $(this).next('p').text('Файл удовлетворяет требованиям и будет отправлен');
  $(this).next('p').css('color','green');
}
else {
  if ($(this).next('p')) {
    $(this).next('p').text('');
  }
}
Аноним
Аноним
Спасибо за помощь!
Аноним
Аноним
Здравствуйте Александр. Не могли бы Вы подсказать обработчик для простейшей формы: нет никаких ввода чего либо, только каптча.
Есть такой index.php:
<!DOCTYPE html>
<html>

<head>
  <title>reCAPTCHA</title>
  <script src='https://www.google.com/recaptcha/api.js'></script>
</head>

<body>
  <center>
    <form method="POST" action="go.php">
      <div class="g-recaptcha" data-sitekey="6Le7DQcUAAAAAD-IPHVHF_B84qcWaQKlMvqS_krZ"></div>
      <center><button type="submit" name="register" id="allpageinside_a_s_b_alongone" id="body_the_sign_up_button_captcha">Register</button></center>
    </form>
  </center>
</body>

</html>
Задача следующая: экшн ведет на go.php (например), при клике по кнопке без каптчи должна появиться ошибка-напоминание, что без каптчи никто никуда не пойдет? или просто переход не должен произойти.
Если каптча разгадана, то тогда осуществляется переход на go.php.
При переходе по прямому адресу site.ru/go.php вход не должен произойти, если можно сделать что-то типа переадресации на страницу с каптчей, в случае попытки захода на go.php минуя каптчу.

Все, что находил в сети, не подходит… Переделать — не хватает знаний.
Если Вам не сложно, и если эта задача действительно не сложная, то не могли бы помочь?
Аноним
Аноним
или другой вариант: всё на одной странице. Содержимое индекса не должно быть видимым пока не будет пройдена каптча.
Т.е заходим на index.php и там каптча, после ввода каптчи в этом же index.php открывается уже содержание страницы, а каптча исчезает.
Видел на одном сайте такое. Скорее всего это будет проще сделать, чем первый вариант. И этот вариант даже будет лучше.
И там тоже нажатие кнопки без каптчи не дает никакой результат, только после ввода каптчи появляется соджержимое страницы. А каптча исчезает.
И пока находимся на этой странице — каптчи нет. При новом заходе на страницу каптча снова есть.
Помогите решить задачу, а то уже перерыл весь гугл, и наш и зарубежный — нет таких вариантов, даже близко.
Аноним
Аноним
Вот вариант одностраничный:
<?php 
if (isset($_POST['submit'])) {
  $secret = '6LfE5hQTAAAAAIU5P_IQjg8JIZ_x4Rd4dSzysgSC';
  $response = $_POST['g-recaptcha-response'];
  $remoteip = $_SERVER['REMOTE_ADDR']; 
  $url = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secret&response=$response&remoteip=$remoteip");
  $result = json_decode($url, TRUE);
  if ($result['success'] == 1) {
    echo $_POST['myreq'];
  }
}
?>
<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Google reCAPTCHA</title>
</head>

<body>
  <form action="" method="post">
    <input type="text" name="myreq">
    <div class="g-recaptcha" data-sitekey="6LfE5hQTAAAAAH2Aj5lMPSA4yUQzsEDGxoJbV4Ib"></div>
    <input type="submit" name="submit" value="Send Request!">
  </form>

  *ТУТ содержание страницы, которое не видно до ввода каптчи*

</body>
<script src='https://www.google.com/recaptcha/api.js'></script>

</html>
Нужно сделать без поля ввода текста и чтобы после ввода каптчи она исчезала и появлялось основное содержание страницы
Александр Мальцев
Александр Мальцев
Это будет выглядеть следующим образом:
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>

<?php
$showform = true;
if (isset($_POST['g-recaptcha-response'])) {
  // ваш секретный ключ
  $secret = 'ваш_секретный_код';
  require_once (dirname(__FILE__).'/recaptcha/autoload.php');
  // создать экземпляр службы recaptcha, используя секретный ключ
  $recaptcha = new \ReCaptcha\ReCaptcha($secret);
  // получить результат проверки кода recaptcha
  $resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
  // если результат положительный, то...
  if ($resp->isSuccess()){
    $showform = false;
    ?>

    <!-- HTML-код, который будет отображаться при правильном вводе капчи  -->
    <p>Контент страницы...</p> 

    <?php
  } 
}
if ($showform==true) {
?>

<!-- Форма с гугловской рекапчей -->
<form action="<?php echo $_SERVER['REQUEST_URI']; ?>" id="captchaForm" method="post">
  <!-- Google reCAPTCHA -->
  <div class="g-recaptcha" data-sitekey="ваш_site_код"></div>
  <button name="send-message" type="submit" class="btn btn-primary pull-right">Отправить</button>
</form><!-- Конец формы -->

<?php
}
?>

<script src='https://www.google.com/recaptcha/api.js'></script>
</body>
</html>
Вместо ваш_секретный_код и ваш_site_код вставить соответствующие ключи Google reCaptcha.
Александр Мальцев
Александр Мальцев
Это осуществляется так.
1 файл (например, index.html):
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>

<!-- Форма с гугловской рекапчей -->
<form action="go.php" id="messageForm" method="post">
  <!-- Google reCAPTCHA -->
  <div class="g-recaptcha" data-sitekey="ваш_сайт_код"></div>
  <button name="send-message" type="submit" class="btn btn-primary pull-right">Отправить</button>
</form><!-- Конец формы -->

<script src='https://www.google.com/recaptcha/api.js'></script>

</body>
</html>
2 файл (например, go.php). Он будет проверять код reCaptcha. В случае ошибки, переправлять его (пользователя) на страницу, содержащую капчу гугл. В случае успеха, отображать содержимое этой формы.
<?php
$showError = true;
if (isset($_POST['g-recaptcha-response'])) {
  $secret = 'ваш_секретный_ключ';
  require_once (dirname(__FILE__).'/recaptcha/autoload.php');
  // создать экземпляр службы recaptcha, используя секретный ключ
  $recaptcha = new \ReCaptcha\ReCaptcha($secret);
  // получить результат проверки кода recaptcha
  $resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
  // если результат положительный, то...
  if ($resp->isSuccess()){
    $showError = false;
  }
}
if ($showError==true) {
  header('Location: http://site.ru/index.php');
  exit;
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>

<?php
if ($showError==false) {
?>

<!-- HTML-код, который будет отображаться при правильном вводе капчи  -->
<p>Контент страницы...</p> 

<?php
}
?>

</body>
</html>
Аноним
Аноним
Что-то не идет: feex.ru/test/ — это вариант с файлом go
feex.ru/test/index2.php — это Ваш первый код
Александр Мальцев
Александр Мальцев
Конечно не пойдёт, библиотеку recaptcha вы же не скопировали в свой проект.
Аноним
Аноним
Не скопировал)
Теперь всё работает. Спасибо)
Аноним
Аноним
Александр, пытаемся сделать форму заказа обратного звонка.
Добавили на форму HTML:
HTML:
<div class="row">
  <div class="col-sm-12">
    Перезвоните мне пожалуйста
  </div>
</div>
<div class="row">
  <div class="col-sm-6">
    <div class="form-group">
      с <input type="time" id="timestart" name="timestart" class="form-control" required="required" min="" max="22:00" value="">
    </div>
  </div>
  <div class="col-sm-6">
    <div class="form-group">
      до <input type="time" id="timeend" name="timeend" class="form-control" required="required" min="" max="22:00" value="">
    </div>
  </div>
</div>

И написали простановку значений для этих двух полей.
JavaScript:
<script>
//какое завтра будет число?
var d = new Date();
day = d.getDate() + 1;
month = d.getMonth() + 1;
year = d.getFullYear();
DateToCall = (day + "." + month + "." + year +"г.");
//Начало и Конец рабочего дня
var wdstart = 8;
var wdend = 18;
//Текущее время
var totalSec = new Date().getTime() / 1000;
var hours = parseInt( totalSec / 3600 ) % 24+4;
var hoursend = hours + 1;
var minutes = parseInt( totalSec / 60 ) % 60;
//Начало периода времени звонка
var tstart = (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes);
//Конец периода времени звонка
var tend = (hoursend < 10 ? "0" + hoursend : hoursend) + ":" + (minutes < 10 ? "0" + minutes : minutes);
//Устанавливаем значения для начала периода звонка
timestart.setAttribute('min', tstart);
timestart.setAttribute('value', tstart);
//Устанавливаем значения для конца периода времени звонка
timeend.setAttribute('min', tend);
timeend.setAttribute('value', tend);
</script>

Оно вроде бы все замечательно. берет текущее время, проставляет его в поле с началом, прибавляет к текущему времени 1 час, проставляет его в поле с концом, все замечательно, тут вопросов нет, но, допустим пользователь зашел на сайт после 18:00, когда рабочий день закончен, и почту никто не прочитает сегодня, вот тут и заковырка, как сделать так, чтобы если пользователь заказывает звонок после окончания рабочего дня, но до 23:59, то ему надо сказать, что позвонят ему только завтра и начало и конец выставить, соответственно 8:00 и 22:00.
Если пользователь — полуночник и запрашивает звонок в период между 00:00 и 7:59 то начало и конец — также выставить на 8:00 и 22:00.
Если запрашивает с 8:00 до 18:00 — то по принципу, как сейчас.
Как это можно реализовать?
Аноним
Аноним
UPD: Поколдовал сам, получилось вот так.
HTML:
<div class="row">
  <div class="col-sm-12">
    Перезвоните мне пожалуйста <span id="when"></span><input type="hidden" id="cday" name="cday" value="">
  </div>
</div>
<div class="row">
  <div class="col-sm-6">
    <div class="form-group">
      с <input type="time" id="timestart" name="timestart" class="form-control" required="required" min="" max="22:00" step="1"
        value="">
    </div>
  </div>
  <div class="col-sm-6">
    <div class="form-group">
      до <input type="time" id="timeend" name="timeend" class="form-control" required="required" min="" max="22:00" step="1"
        value="">
    </div>
  </div>
</div>

JavaScript:
<script>
  //какое послезавтра будет число?
  var b = new Date();
    b.setDate(b.getDate()+2);
    atday = b.getDate();
    atmonth = b.getMonth() + 1;
    atyear = b.getFullYear();
    aTomorrowСall = (atday + "." + (atmonth < 10 ? "0" + atmonth : atmonth) + "." + atyear + "г.");
    
  //какое завтра будет число и день недели?
  var a = new Date();
    a.setDate(a.getDate()+1);
    tday = a.getDate();
    tmonth = a.getMonth() + 1;
    tyear = a.getFullYear();
    TomorrowСall = (tday + "." + (tmonth < 10 ? "0" + tmonth : tmonth) + "." + tyear + "г.");
    TomorrowWeekDay = a.getDay();
  //А сегодня какое число и день недели?
  var d = new Date();
    day = d.getDate();
    month = d.getMonth() + 1;
    year = d.getFullYear();
    TodayCall = (day + "." + (month < 10 ? "0" + month : month) + "." + year +"г.");
    TodayWeekDay = d.getDay();
  //Начало и Конец рабочего дня
  var wdstart = 8;
  var wdend = 18;
  var lasthour = wdend - 1;
  //Текущее время
  var totalSec = new Date().getTime() / 1000;
  var hours = parseInt( totalSec / 3600 ) % 24+4;
  var hoursend = hours + 1;
  var minutes = parseInt( totalSec / 60 ) % 60;
  //Начало периода времени звонка
  var tstart = (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes);
  //Конец периода времени звонка
  var tend = (hoursend < 10 ? "0" + hoursend : hoursend) + ":" + (minutes < 10 ? "0" + minutes : minutes);
  
  //Если сейчас рабочее время
  if (hours >= wdstart) {
    if (hours < wdend) {
      //Если сегодня воскресение
      if (TodayWeekDay = 0) {
        //Показываем, что пользователь заказывает звонок на завтра
        when.innerHTML = ('завтра ' + TomorrowСall);
        //Устанавливаем дату звонка - завтра
        cday.setAttribute('value', TomorrowСall);
        //Устанавливаем значения для начала периода звонка
        timestart.setAttribute('min', '08:00');
        timestart.setAttribute('value', '08:00');
        //Устанавливаем значения для конца периода времени звонка
        timeend.setAttribute('min', '22:00');
        timeend.setAttribute('value', '22:00');
      }
      else {
          //А вдруг запрос звонка происходит в последние 10 минуты рабочего времени
          if (hours >= lasthour) {
            if (minutes > 50) {
              //А вдруг это последние рабочие минуты субботы?
              if (TodayWeekDay = 6) {
                //Показываем, что пользователь заказывает звонок на послезавтра
                when.innerHTML = ('завтра ' + аTomorrowСall);
                //Устанавливаем дату звонка - послезавтра
                cday.setAttribute('value', аTomorrowСall);
                //Устанавливаем значения для начала периода звонка
                timestart.setAttribute('min', '08:00');
                timestart.setAttribute('value', '08:00');
                //Устанавливаем значения для конца периода времени звонка
                timeend.setAttribute('min', '22:00');
                timeend.setAttribute('value', '22:00');
              }
              else {
                  //Показываем, что пользователь заказывает звонок на завтра
                  when.innerHTML = ('завтра ' + TomorrowСall);
                  //Устанавливаем дату звонка - завтра
                  cday.setAttribute('value', TomorrowСall);
                  //Устанавливаем значения для начала периода звонка
                  timestart.setAttribute('min', '08:00');
                  timestart.setAttribute('value', '08:00');
                  //Устанавливаем значения для конца периода времени звонка
                  timeend.setAttribute('min', '22:00');
                  timeend.setAttribute('value', '22:00');	
              }
            }
          }
          else {
            //Устанавливаем дату звонка - сегодня
            cday.setAttribute('value', TodayCall);
            //Устанавливаем значения для начала периода звонка
            timestart.setAttribute('min', tstart);
            timestart.setAttribute('value', tstart);
            //Устанавливаем значения для конца периода времени звонка
            timeend.setAttribute('min', tend);
            timeend.setAttribute('value', tend);
          }
      }
    }
  }
  
  //Если рабочее время еще не началось
  if (hours < wdstart) {
    //Если сегодня воскресение
    if (TodayWeekDay = 0) {
      //Показываем, что пользователь заказывает звонок на завтра
      when.innerHTML = ('завтра ' + TomorrowСall);
      //Устанавливаем дату звонка - завтра
      cday.setAttribute('value', TomorrowСall);
      //Устанавливаем значения для начала периода звонка
      timestart.setAttribute('min', '08:00');
      timestart.setAttribute('value', '08:00');
      //Устанавливаем значения для конца периода времени звонка
      timeend.setAttribute('min', '22:00');
      timeend.setAttribute('value', '22:00');
    }
    else {
      //Устанавливаем дату звонка - сегодня
      cday.setAttribute('value', TodayCall);
      //Устанавливаем значения для начала периода звонка
      timestart.setAttribute('min', '08:00');
      timestart.setAttribute('value', '08:00');
      //Устанавливаем значения для конца периода времени звонка
      timeend.setAttribute('min', '22:00');
      timeend.setAttribute('value', '22:00');
    }
  }
  //Если рабочее время уже закончилось
  if (hours >= wdend) {
    //А вдруг сегодня суббота?
    if (TodayWeekDay = 6) {
      //Показываем, что пользователь заказывает звонок на послезавтра
      when.innerHTML = ('завтра ' + аTomorrowСall);
      //Устанавливаем дату звонка - послезавтра
      cday.setAttribute('value', аTomorrowСall);
      //Устанавливаем значения для начала периода звонка
      timestart.setAttribute('min', '08:00');
      timestart.setAttribute('value', '08:00');
      //Устанавливаем значения для конца периода времени звонка
      timeend.setAttribute('min', '22:00');
      timeend.setAttribute('value', '22:00');
    }
    else {
      //Показываем, что пользователь заказывает звонок на завтра
      when.innerHTML = ('завтра ' + TomorrowСall);
      //Устанавливаем дату звонка - завтра
      cday.setAttribute('value', TomorrowСall);
      //Устанавливаем значения для начала периода звонка
      timestart.setAttribute('min', '08:00');
      timestart.setAttribute('value', '08:00');
      //Устанавливаем значения для конца периода времени звонка
      timeend.setAttribute('min', '22:00');
      timeend.setAttribute('value', '22:00');
    }
}
</script>

Все отлично, протестировал, работает как надо.
Вопрос, а как сделать так, чтобы этот скрипт срабатывал не при загрузке страницы, а при открытии модального окна с формой?
Александр Мальцев
Александр Мальцев
Если вы используете Bootstrap Modal, то ваш код необходимо поместить в следующий:
//exampleModal - id модального окна
$('#exampleModal').on('show.bs.modal', function (event) {
  //...
})
Аноним
Аноним
Благодарю
Аноним
Аноним
Все вроде отлично работает. Но имел неосторожность протестировать на iphone.
Вскрылся баг. Safari не обращает никакого внимания на установленные скриптом значения, а именно не отображает value установленное скриптом, и не обращает внимания на то, что скрипт устанавливал значения min/
Может есть способы побороть?
Аноним
Аноним
UPD:
И Хром на Андроиде тоже подкосячивает, он вроде-как все значения атрибутов устанавливает, но установленное скриптом значение value не отображает (надообязательно тыкнуться в поле и «подтвердить»).
Александр Мальцев
Александр Мальцев
Может быть проще было бы написать с помощью jQuery.

Работа с value в JavaScript осуществляется как свойством:
//получить значение свойства value
var value = document.getElementById('name').value;
// установить значение свойству value
document.getElementById('name').value = '08:00';
Добавление своих пользовательских атрибутов осуществляется с помощью data-. Т.е. data-min и data-max.
Аноним
Аноним
Может быть и проще с помощью jQuery, но я и в js-то валенок.
С показом value, кстати не помогло через document.getElementById они устанавливаются, но не отображаются в полях (iphone + Safari и Android + Chrome).

По поводу min и max — так вроде это не пользовательские атрибуты они вроде в спецификации HTML5 есть. и они отрабатываются в текущем виде на Android + Chrome, а вот Safari на iPhone их игнорит.
Александр Мальцев
Александр Мальцев
Немного не то имел ввиду.
Когда вы устанавливаете значение value, обращаться к нему необходимо как к свойству, а не как к атрибуту:
// т.е. вместо
cday.setAttribute('value', TomorrowСall);
// использовать следующее
cday.value = TomorrowСall;
Такие атрибуты в HTML5 есть, но вот их поддержка осуществляется только несколькими браузерами (Edge, Chrome, Opera и Android 4.4+). _http://caniuse.com/#search=date
Аноним
Аноним
Отлично. Благодарю. Теперь выставленные значения отображаются
По поводу min и max — ccылку посмотрел, правильно ли я понимаю, что эти ограничения выставить не получится для Safari на iOS или есть какой-то обходной путь?
Александр Мальцев
Александр Мальцев
Написать скрипт самостоятельно или использовать какой-нибудь готовый плагин для работы с датой (datepicker, datetimepicker или др.), который это поддерживает.
Аноним
Аноним
Александр, приветствую.
Почему-то внезапно перестал отрабатывать скрипт (и соответственно отображать форму). Выдает ошибку Uncaught ReferenceError: аTomorrowСall is not defined.

Не подскажете в чем может быть проблема?
(из изменений были только: поправлены стили кнопки, которая вызывает модельное окно, и само модальное окно перенесено непосредственно под тэг body)

И в локале, где точно ничего не менялось и никуда не двигалось — произошло тоже самое.
Аноним
Аноним
UPD: Причем так себя ведет когда скрипт запускается по открытии модального окна
jQuery(function($) {
$('#CallBackFrm').on('show.bs.modal', function (event) {
	...
})
});
Александр Мальцев
Александр Мальцев
Посмотрите, на какой строчке возникает ошибка и значения переменных. Она обычно возникает, когда Вы хотите присвоить значение некоторой сущности, для которой это сделать нельзя.
Аноним
Аноним
Это возникает вот в этом месте
//Если рабочее время уже закончилось
  if (hours >= wdend) {
    //А вдруг сегодня суббота?
    if (TodayWeekDay = 6) {
      //Показываем, что пользователь заказывает звонок на послезавтра
      when.innerHTML = ('завтра ' + аTomorrowСall);
И только если скрипт запускаем по открытию модального окна, завернув его в
jQuery(function($) {
$('#CallBackFrm').on('show.bs.modal', function (event) {
	...
})
});
Причем, возникать оно начало «само-по-себе» ничего, что могло бы повлиять не происходило, как и сказал выше.
Если убираем «обертку»
jQuery(function($) {
$('#CallBackFrm').on('show.bs.modal', function (event) {
	...
})
});
То все работает, никаких ошибок не возникает.
Александр Мальцев
Александр Мальцев
Знак равенства в Javascript — это == (два знака равно). А у вас в if только один.
Аноним
Аноним
Правильно-ли я понимаю, что два знака равно должно быть в строчке
if (TodayWeekDay = 6) {
?
Если да, то все стает еще интереснее. Исчезает ошибка, но если вызов окна происходит после 17:00 (конец рабочего дня), то никакие значения полям не выставляются,
when.innerHTML = ('завтра ' + аTomorrowСall);
тоже не отрабатывает.
Аноним
Аноним
Пока вопрос снят.
Дело было в путях к jQuery.
Аноним
Аноним
Александр, приветствую.

Столкнулся с такой проблемой.
Если на странице 1 модальное окно с формой, — то все отлично.
Если же на странице больше 1 модального окна с формами то Рекапча отображается только в самом первом, в остальных не отображается.
Можно-ли это как-то побороть?
Александр Мальцев
Александр Мальцев
Для решения проблемы воспользуйтесь этим комментарием.
Аноним
Аноним
Отлично, отображается. благодарю.
Аноним
Аноним
Здравствуйте! Подскажите пожалуйста, как сделать, чтобы можно было загружать фотографии большого размера до 10шт. по 10 мб. я поменял $maxSizeFile = 10485760; в трех местах в файле script и process. Когда отправляю сообщение с прикрепленным файлом в 7мб выдает ошибку «Произошла ошибка при отправке формы на сервер.». Если я правильно понимаю, то это из за того, что не отправляется такой файл по почте. Мне не обязательно получать на почту. Можно просто ссылкой.
Александр Мальцев
Александр Мальцев
Попробуйте установить следующие директивы в php.ini:
upload_max_filesize = 10M
post_max_size = 10M
А также в файле .htaccess:
php_value upload_max_filesize 10M
php_value post_max_size 10M
Аноним
Аноним
Добавил только в .htaccess Все работает благодарю за подсказку и собственно за форму!
Еще такой вопрос: можно сделать так, чтоб была показана загрузка или хотя бы стрелка мышки в песочные часы переключалась. т.к. не понятно нажал «отправить» или нет?
Александр Мальцев
Александр Мальцев
Как это сделать, можно посмотреть в этом комментарии. Там же приведён готовый пример формы обратной связи с вращающейся иконкой.
Аноним
Аноним
И Александр, будьте добры, подскажите, как будет правильней сформировать две формы на одной странице.
Одна полностью будет повторять тот функционал, который у вас есть. А на второй будут только два поля: имя и номер телефона.

P.s. Сразу не понял, почему у меня не работает отправка, когда разместил обе формы. Просто проверка полей в первой проходит, а во второй они пустые. Поэтому отправки нет(((
Александр Мальцев
Александр Мальцев
В файле script.js отправку формы осуществляет следующий обработчик:
// #messageForm - id формы
$('#messageForm').submit(function (event) {
  //...
});
Следовательно, необходимо сделать 2 таких обработчика. Один для одной формы, другой для другой.
Далее сделать 2 файла для обработки формы на стороне сервера (например, process.php и process2.php). Или использовать один php-файл, но тогда необходимо проверять с какой формы пришёл ответ, и обрабатывать уже именно её.

Кроме этого, если Вы собираетесь использовать в каждой форме Google reCaptcha, то проделать ещё следующее:
1. Каждому блоку reCaptcha дать идетификатор:
<!-- Например, для 1 формы -->
<div id="recaptcha1"></div>

<!-- Например, для 2 формы -->
<div id="recaptcha2"></div>
2. Использовать скрипт для отрисовки 2 гугловских капч
<script src="https://www.google.com/recaptcha/api.js?onload=myCallBack&render=explicit" async defer></script>
<script>
  var recaptcha1;
  var recaptcha2;
  var myCallBack = function() {
    // отрисовка recaptcha1 на элементе с id="recaptcha1"
    recaptcha1 = grecaptcha.render('recaptcha1', {
      'sitekey' : 'ваш ключ site_key' 
    });
    // отрисовка recaptcha2 на элементе с id="recaptcha2"
    recaptcha2 = grecaptcha.render('recaptcha2', {
      'sitekey' : 'ваш ключ site_key' 
    });
  };
</script>
3. Проверять капчу на сервере.
Аноним
Аноним
Простите Александр, но я совсем туговат в этом плане. Вторую форму на страницу добавил. Дал ей имя messageForm1. Весь код первой формы скопировал один в один.

Код для рекапчи вставил, спасибо, обе показываются.

В script.js скопировал обработчик, который вы написали. Опять же сменил всего лишь messageForm на messageForm1. Но вторая форма ничего не делает при нажатии на «Отправить сообщение». Первая работает.

Александр, если Вас не затруднит, напишите пожалуйста правильный script.js для моего случая. Формы одинаковые. Заранее спасибо.
Аноним
Аноним
Александр, прошу прощения за беспокойство, во всем разобрался. Большое Вам спасибо, за то что комментируете ваш код. Даже не зная только javascript и php, добился нужного себе результата.
Спасибо за Ваш труд!
Аноним
Аноним
Александр, здравствуйте.

Подскажите, пожалуйста, почему так происходит. Добавляю изображения к сообщению в форме. Они сохраняются в папку files на сервере, но не приходят в письме. Куда нужно смотреть?

Заранее спасибо.
Александр Мальцев
Александр Мальцев
В файле process.php измени этот код
// прикрепляем файл к письму
if (isset($file)) {
  $mail->addAttachment($file);
}
на следующий:
// прикрепляем файлы к письму
if (isset($files)) {
  foreach ($files as $value) {
    $mail->addAttachment($value);
  }
}
Аноним
Аноним
Александр, спасибо большое, за столь быстрый ответ. И прошу прощения, что сам так долго отвечал…
Все работает :)
Аноним
Аноним
здравствуйте.
подскажите, пожалуйста, что надо изменить в форме, чтоб поля для файлов показывались не по мере добавления файлов, а все сразу?
Александр Мальцев
Александр Мальцев
В файле script.js удалите следующий кусок кода:
// если выбран файл, то добавить ещё элемент "Выбрать файл"
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>');
}
В файл index.html после строчек:
<input type="file" name="images[]">
<p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>
добавьте ещё 4 точно таких же:
<input type="file" name="images[]">
<p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>
<input type="file" name="images[]">
<p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>
<input type="file" name="images[]">
<p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>
<input type="file" name="images[]">
<p style="margin-top: 3px; margin-bottom: 3px; color: #ff0000;"></p>
Аноним
Аноним
огромное Вам спасибо!
Аноним
Аноним
Будь Здрав, Шеф!
Немного офтопа) Можешь подсказать хорошую литературу, чтобы с нуля изучить php. Хочу такие же вещи как ты вытворять в modx)
В меню не хватает иконки для php)
Лучи добра)
Александр Мальцев
Александр Мальцев
Изучать php можно с любой книги из серии для ничинающих. По структуре они примерно все одинаковые. Выбирай ту из них которая ближе к тебе по написанию.
Аноним
Аноним
Александр. Благодарю.
Наверное навязчив и назойлив, но хочется больше «красоты», можно-ли как-то сделать так, чтобы див с рекапчей появлялся только тогда, когда все поля формы заполнены.
Александр Мальцев
Александр Мальцев
В этом случае придётся немного изменить html-документ и js-скрипт.
1. Добавить класс hidden к капчи и сообщению:
<center>
  <div class="g-recaptcha hidden" data-sitekey="публичный_ключ"></div>
</center>
<p class="text-danger hidden" id="msg"></p>
2. Добавить в script.js после загрузки страницы такой код:
if ($('.g-recaptcha').hasClass('hidden')) {
  var result = {};
  $('#messageForm input,#messageForm textarea').change(function(){
    //найти предков, имеющих класс .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');
      result[this.id]=true;
    } 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');
      result[this.id]=false;
    }
    var showCaptcha = true;
    if (Object.keys(result).length==5) {
      $.each(result,function(key,value){
        if (value==false) {
          showCaptcha = false;
          return false;
        }
      });
      if (showCaptcha) {
        $('.g-recaptcha').removeClass('hidden');
        $('#msg').removeClass('hidden');
      }
    }
  });
}
Принцип здесь простой. Проверяем каждый элемент после его изменения и записываем результаты в объект result. После этого проверяем количество ключей в объекте. Если их количество равно 5, то проверяем все ли они прошли валидацию. Если да, то отображаем гугл капчу.

HTML и JavaScript код формы обратной связи
Аноним
Аноним
Отлично, все прекрасно работает.
Александр, подскажите, где что нужно поправить в коде js и php если нам не надо отправлять файлы, но есть еще два поля, например с телефоном и адресом сайта пользователя. Если содержимое формы выглядит так.
HTML:
<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="row">
    <div class="col-sm-6">
      <!-- Телефон -->
      <div class="form-group has-feedback">
        <label for="name" class="control-label">Введите ваш телефон:</label>
        <input type="phone" id="phone" name="phone" class="form-control" required="required" value="" placeholder="+7 (901) 123-45-67"
          pattern="^\+\d{1,3}(|\s)\(\d{1,5}\)(|\s)\d{1,3}[\- ]\d{2}[\- ]\d{2}$">
        <span class="glyphicon form-control-feedback"></span>
      </div>
    </div>
    <div class="col-sm-6">
      <!-- Адрес сайта -->
      <div class="form-group has-feedback">
        <label for="email" class="control-label">Введите адрес вашего сайта:</label>
        <input type="url" id="siteurl" name="siteurl" class="form-control" required="required" value="" placeholder="Например, www.google.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 style="margin-top: 3px; margin-bottom: 3px;">
  <center>
    <div class="g-recaptcha" data-sitekey="6LepjAsTAAAAAFZqccY0ZiGqc3XEd3YNxo8cHsHX"></div>
  </center>
  <p class="text-danger" id="msg"></p>
  <!-- Кнопка, отправляющая форму по технологии AJAX -->
  <button name="send-message" type="submit" class="btn btn-primary pull-right">Отправить сообщение</button>
</form>
<!-- Конец формы -->
Александр Мальцев
Александр Мальцев
Изменил форму. Убрал возможность прикрепления файлов к ней, а также добавил новые поля (телефон и адрес сайта из Вашего шаблона).
Скачать по ссылке: форму обратной связи с телефоном для сайта.

Кстати в Вас в HTML шаблоне 2 опечатки в атрибуте for.
Аноним
Аноним
Про опечатки — согласен, не уследил за ctrl+c + ctrl+v