Простой пример контактной формы, проверенной Google reCAPTCHA v3 с чистым JavaScript и PHP
tldr;пропустите код внизу.
Соответствующие документы reCAPTCHA и т. д .:
(Если Google слушает, нам нравится ваша работа, и было бы замечательно, если бы вы добавили несколько более сложных примеров, связанных с вышеуказанными страницами, пожалуйста.)
Обзор:
- Получите ключи от Google
- Загрузите recaptcha / api.js в заголовок html
- Отправьте форму Hijack с помощью JavaScript и затем получите токен изGoogle
- Отправьте форму с токеном на ваш сервер
- Отправьте запрос из бэкэнда вашего веб-сайта в Google, чтобы подтвердить отправку формы
- Интерпретируйте ответ и при необходимости выполните
Важное замечание: параметр ответа 'success' указывает только то, была ли проверена капча успешно, но не указывает, была ли отправка спамом или нет.
параметр "Score" - это результат, о котором вам нужно знать.Чем выше оценка (число от 0 до 1), тем больше вероятность того, что отправка является подлинной, и вам решать, какой порог (например, 0,5) принять.
Подробно:
ДобавьтеСледующая строка заголовка вашего HTML для загрузки кода recaptcha api.js:
<script src="https://www.google.com/recaptcha/api.js?render=$reCAPTCHA_site_key"></script>
(где $reCAPTCHA_site_key
- ваш публичный «ключ сайта», который я сохранил в «config.php»).'file.)
Вам необходимо отправить токен (полученный от Google и уникальный для каждой отправки формы) на ваш сервер.Я думаю, что проще всего отправить его через POST вместе с остальными данными формы.Для этого я добавляю скрытое поле в форме:
<form id="contactForm" method="post" action="contact">
<!-- other form inputs -->
<input type="hidden" id="gRecaptchaResponse" name="gRecaptchaResponse">
<input type="submit" name="contact_submit" value="Send message">
</form>
(примечание: "contact" - это contact.php, но я "переписал" URL с помощью .htaccess)
Теперь нам нужно перехватить отправку формы по умолчанию для генерации токена.Мы могли бы сгенерировать токен при загрузке страницы, но так как токен действителен только в течение двух минут (если я правильно читаю страницу https://developers.google.com/recaptcha/docs/verify), я думаю, что лучше получить его в момент необходимости отправить его наСервер вашего сайта.
С этой целью я добавил следующее сразу после тега закрывающей формы:
<script>
contactForm.addEventListener('submit', event => {
event.preventDefault()
validate(contactForm)
});
</script>
Я поместил функцию validate(form)
непосредственно перед закрывающим тегом тела:
function validate(form) {
//perform optional error checking on form. If no errors then request a token and put it into the hidden field
getRecaptchaToken(form)
}
//some other (optional) form validation functions
function getRecaptchaToken(form) {
grecaptcha.ready(function() {
grecaptcha.execute($reCAPTCHA_site_key, {action: 'contactForm'}).then(function(token) {
gRecaptchaResponse.value = token //set the value of the hidden field
form.submit() //submit the form
});
});
}
Примечания:
$reCAPTCHA_site_key
- ваш общедоступный ключ сайта action: 'contactForm'
определяет представление этой конкретной формы впанель инструментов Google reCAPTCHA и подтверждение того, что она соответствует ожидаемой в бэкэнде, является рекомендуемым дополнительным шагом безопасности
В основном файле PHP при получении отправки формы:
//get the IP address of the origin of the submission
$ip = $_SERVER['REMOTE_ADDR'];
//construct the url to send your private Secret Key, token and (optionally) IP address of the form submitter to Google to get a spam rating for the submission (I've saved '$reCAPTCHA_secret_key' in config.php)
$url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($reCAPTCHA_secret_key) . '&response=' . urlencode($g_recaptcha_response) . '&remoteip=' . urlencode($ip);
//save the response, e.g. print_r($response) prints { "success": true, "challenge_ts": "2019-07-24T11:19:07Z", "hostname": "your-website-domain.co.uk", "score": 0.9, "action": "contactForm" }
$response = file_get_contents($url);
//decode the response, e.g. print_r($responseKeys) prints Array ( [success] => 1 [challenge_ts] => 2019-07-24T11:19:07Z [hostname] => your-website-domain.co.uk [score] => 0.9 [action] => contactForm )
$responseKeys = json_decode($response, true);
//check if the test was done OK, if the action name is correct and if the score is above your chosen threshold (again, I've saved '$g_recaptcha_allowable_score' in config.php)
if ($responseKeys["success"] && $responseKeys["action"] == 'contactForm') {
if ($responseKeys["score"] >= $g_recaptcha_allowable_score) {
//send email with contact form submission data to site owner/ submit to database/ etc
//redirect to confirmation page or whatever you need to do
} elseif ($responseKeys["score"] < $g_recaptcha_allowable_score) {
//failed spam test. Offer the visitor the option to try again or use an alternative method of contact.
}
} elseif($responseKeys["error-codes"]) { //optional
//handle errors. See notes below for possible error codes
//personally I'm probably going to handle errors in much the same way by sending myself a the error code for debugging and offering the visitor the option to try again or use an alternative method of contact
} else {
//unkown screw up. Again, offer the visitor the option to try again or use an alternative method of contact.
}
Примечания:
- Это данные, которые будут в ответе от Google (возвращаются как объект JSON):
<code>
{
"success": true|false, // whether this request was a valid reCAPTCHA token for your site
"score": number // the score for this request (0.0 - 1.0)
"action": string // the action name for this request (important to verify)
"challenge_ts": timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"hostname": string, // the hostname of the site where the reCAPTCHA was solved
"error-codes": [...] // optional
}
- Это возможные коды ошибок:
- missing-input-secret: секретный параметр отсутствует.
- invalid-input-secret: секретный параметр недействителен или имеет неправильный формат.
- missing-input-response: параметр ответа отсутствует.
- invalid-input-response: параметр ответа недействителен или имеет неправильный формат.
- bad-request: запрос недействителен или имеет неправильный формат.
- timeout-or-duplicate: Theответ больше не действителен;либо слишком старый, либо использовался ранее.
Собираем все вместе:
contact.php
<?php //contact.php
require_once('config.php');
//do server-side validation of other form fields
if (/*form has been submitted and has passed server-side validation of the other form fields*/) {
$ip = $_SERVER['REMOTE_ADDR'];
$url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($reCAPTCHA_secret_key) . '&response=' . urlencode($g_recaptcha_response) . '&remoteip=' . urlencode($ip);
$response = file_get_contents($url);
$responseKeys = json_decode($response, true);
if ($responseKeys["success"] && $responseKeys["action"] == 'contactForm') {
if ($responseKeys["score"] >= $g_recaptcha_allowable_score) {
//send email with contact form submission data to site owner/ submit to database/ etc
//redirect to confirmation page or whatever you need to do
} elseif ($responseKeys["score"] < $g_recaptcha_allowable_score) {
//failed spam test. Offer the visitor the option to try again or use an alternative method of contact.
}
} elseif($responseKeys["error-codes"]) { //optional
//handle errors. See notes below for possible error codes
//(I handle errors by sending myself an email with the error code for debugging and offering the visitor the option to try again or use an alternative method of contact)
} else {
//unkown screw up. Again, offer the visitor the option to try again or use an alternative method of contact.
}
exit;
} else { //(re)display the page with the form
echo <<<_END
<!DOCTYPE html>
<html lang="en">
<head>
<title>Contact | Your website</title>
<link rel="stylesheet" href="css/style.css">
<script src="https://www.google.com/recaptcha/api.js?render=$reCAPTCHA_site_key"></script>
</head>
<body>
<!-- header etc -->
<form id="contactForm" method="post" action="contact">
//other form inputs
<input type="hidden" id="gRecaptchaResponse" name="gRecaptchaResponse">
<input type="submit" name="contact_submit" value="Send message">
</form>
<script>
contactForm.addEventListener('submit', event => {
event.preventDefault()
validate(contactForm)
});
</script>
<!-- footer etc -->
<script>
function validate(form) {
//perform optional client-side error checking of the form. If no errors are found then request a token and put it into the hidden field. Finally submit the form.
getRecaptchaToken(form)
}
//some (optional) form field validation functions
function getRecaptchaToken(form) {
grecaptcha.ready(function() {
grecaptcha.execute($reCAPTCHA_site_key, {action: 'contactForm'}).then(function(token) {
gRecaptchaResponse.value = token
form.submit()
});
});
}
</script>
</body>
</html>
_END;
config.php
<?php //config.php
//other site settings
// Google reCAPTCHA v3 keys
// For reducing spam contact form submissions
// Site key (public)
$reCAPTCHA_site_key = 'N0t-a-real-0N3_JHbnbUJ-BLAHBLAH_Blahblah';
// Secret key
$reCAPTCHA_secret_key = 'N0t-a-real-0N3_i77tyYGH7Ty6UfG-blah';
// Min score returned from reCAPTCHA to allow form submission
$g_recaptcha_allowable_score = 0.5; //Number between 0 and 1. You choose this. Setting a number closer to 0 will let through more spam, closer to 1 and you may start to block valid submissions.