reCAPTCHA для eForm

Привет всем!
Когда вышла новая версия reCAPTCHA от Google, я решил прикрутить ее к сниппету eForm.
Сделать это оказалось намного проще, чем я думал. Thank you Google! :-)

По порядку:
1) Прежде всего нужно получить ключи для сайта (siteKey и secretKey) — здесь
2) Скачиваем готовую PHP библиотеку каптчи здесь: github (Clone or download, Download ZIP)
3) Из архива, вытаскиваем папку src, закачиваем в папку /assets/snippets и переименовываем эту папку в recaptcha
4) Создаем сниппет ReCaptcha и вставляем в него данный код:
<?php
if(!defined('MODX_BASE_PATH')) {die('What are you doing? Get out of here!');}
include_once MODX_BASE_PATH.'assets/snippets/recaptcha/autoload.php';

if(!defined('siteKey')) {define('siteKey', 'siteKeyCodestring');}
if(!defined('secretKey')) {define('secretKey', 'secretKeyCodestring');}

$lang = isset($lang) ? $lang : 'ru';
$text = isset($text) ? $text : 'Вы не подтвердили, что вы не робот!';

unset($_SESSION['veriword']);

$script = '<script src="https://www.google.com/recaptcha/api.js?hl='.$lang.'"></script>';
$modx->regClientStartupScript($script);

$Recaptcha = new \ReCaptcha\ReCaptcha(secretKey);
  if(isset($_REQUEST['g-recaptcha-response'])){
	  $resp = $Recaptcha->verify($_REQUEST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
	  if ($resp->isSuccess()){
		  $_SESSION['veriword'] = $_SESSION['eForm.VeriCode'];
		  $_POST['vericode'] = $_SESSION['eForm.VeriCode'];
	  } else {
		  $response = $resp->getErrorCodes();            
		  if (!empty($response))
		  {
			  $codes='';
			  foreach ($response as $code) { $codes.= $code; }
			  $_SESSION['veriword'] = 'ReCaptchaErrors : '.$codes;  
		  }
	  }
  }
	
if (!function_exists('setReCaptcha')) {
	function setReCaptcha(&$fields){
		
		$fields['ReCaptcha']= '<div class="g-recaptcha" data-sitekey="'.siteKey.'"></div>';
		return true;
		
	}
}

if (!function_exists('verifyReCaptcha')) {
	function verifyReCaptcha(&$fields,&$vMsg,&$rMsg,&$rClass){
		
		 if($_SESSION['veriword'] !== $_SESSION['eForm.VeriCode']){
			$vMsg[] = $text; 
		 }
		return true;
	}
}
?>


5) В темплейты eForm прописываем плейсхолдер [+ReCaptcha+] в том месте, где хотим ее видеть (если вы используете в темплейтах вызов veriword.php, закройте его комментарием или удалите)
6) Перед вызовом eForm ставим вызов сниппета ReCaptcha ([[ReCaptcha]]), а в вызов самого eForm добавляем параметры:
&eFormOnBeforeFormMerge=`setReCaptcha` &eFormOnValidate=`verifyReCaptcha` &vericode=`1`
Только и всего.

27 комментариев

avatar
Подозреваю, что если на странице несколько форм, то работать не будет?
avatar
Да, у меня по одной форме на странице. Ща поправлю)
avatar
Поправил. И, к слову, если на странице больше одной формы, то вызов сниппета ReCaptcha все равно только один на страницу нужен.
avatar
хм… с одной формой всё норм. Вызов сниппета оставил один… но все равно показывается только рекпатча у первой формы, у второй она не показывается
avatar
Спасибо.
  • 1px
  • 0
avatar
Здравствуйте!
Извините, что не разобрался, вроде все легко и понятно.
Поставил все как описано, после включения страница перестает совсем отображаться, в консоли ошибку не показывает, пишет, что невозможно отобразить страницу.
Ключи в теле сниппета прописал в функции define/
Спасибо.
Комментарий отредактирован 2016-09-13 08:51:43 пользователем tmih
  • tmih
  • 0
avatar
Еще вот попробовал в отдельной странице вызвать сниппет капчи и еФорм — теперь видно, что ругается:
Fatal error: Can't use method return value in write context in /home/.../admin/includes/document.parser.class.inc.php(1120): eval()'d code on line 23
это var $documentMethod;
Очень хочется запустить, чтоб заработала.
avatar
Добрый день!
Ключики нужно вписывать вместо siteKeyCodestring и secretKeyCodestring.
Не будет лишним знать версию php, modx и eform.
Кстати, почему /admin/includes/, а не /manager/includes/?
Комментарий отредактирован 2016-09-13 10:00:21 пользователем DrMorro
avatar
PHP Version 5.4.16
eForm 1.4.6
адрес админки поменял- так можно?
ключи — так точно и вписал.
MODX 1.1 последняя официальная версия
Вернул адрес админки, но ошибка осталась
Fatal error: Can't use method return value in write context in /home/.../manager/includes/document.parser.class.inc.php(1120): eval()'d code on line 23
Комментарий отредактирован 2016-09-13 11:04:46 пользователем tmih
avatar
В php до версии 5.5 есть проблемы с empty.
Замените в коде сниппета строчки с empty

if (!empty($resp->getErrorCodes()))
{
$codes='';
foreach ($resp->getErrorCodes() as $code) {
$codes.= $code;
}
$_SESSION['veriword'] = 'ReCaptchaErrors: '.$codes;
}

на

$response = $resp->getErrorCodes();
if (!empty($response))
{
$codes='';
foreach ($response as $code) {
$codes.= $code;
}
$_SESSION['veriword'] = 'ReCaptchaErrors: '.$codes;
}
avatar
Спасибо!!! Заработало :-)
А еще вопрос(больше не буду) — так получается, что например в любой форме(вызов в модальном окне) нажимаешь отправить при пустом ли неправильно заполненном поле имя и тп, выскакивает сообщение о том, что такое-то поле незаполнено, а капчи уже нет, это в том случае, если форма в модальном окне.
А когда форма с этой капчей на странице, то все хорошо.
avatar
Пожалуйста.
Если форма в модальном окне, то капчу нужно принудительно перезагружать. Это уже методы самой reCaptcha (reset reCAPTCHA). Читайте здесь: developers.google.com/recaptcha/docs/display#config
avatar
tmih, вы нашли как после аякса запустить рекапчу?

grecaptcha.reset(), которую предлагает DrMorro не работает, рекапча не перезагружается.
Комментарий отредактирован 2016-10-05 21:35:16 пользователем gumoviy
avatar
Сам написал и сам решил.

Может кому-то пригодится. Как показать recaptcha 2.0 После ajax перезагрузки страницы.

1. Необходимо помимо api.js еще подключить:

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

2. В функции ajax нужно снова перезапустить рекапчу:

На примере [[ajaxSubmit]] помещаем этот код сюда:

}else{
$("#modal_ajax").html(response);
//вставляем сюда
grecaptcha.render(document.getElementById('ID_ВАШЕГО_DIV'), {
'sitekey' : 'ВАШ_КОД_SITEKEY'
});
}


Все, пользуемся.
Комментарий отредактирован 2016-10-05 23:39:17 пользователем gumoviy
avatar
Спасибо, что добавили. Только увидел сообщение. Тогда не решил — немного изменили дизайн и поставили просто на странице, поэтому не писал сюда.
Удачи!
Комментарий отредактирован 2016-10-11 14:32:29 пользователем tmih
avatar
Не выводилась каптча при добавлении скрипта через php:
$script = '<script src="https://www.google.com/recaptcha/api.js?hl='.$lang.'"></script>';
$modx->regClientStartupScript($script);

Добавил ручками в head — заработало.
avatar
Добрый день!
Не могли бы вы подсказать в чем может быть проблема, при отправке письма постоянно происходит ошибка «Неверный код подтверждения.»?
  • Navin
  • 0
avatar
Добрый!
Вы не могли бы сообщить более существенные подробности?
avatar
такая же проблема. вот вызов
<code>[!ReCaptcha!]
		[!eForm? &formid=`order-form`
		&subject=`Заявка на аренду с сайта [(site_url)]`
		&tpl=`orderForm`
		&report=`orderReport`
		&to=`[[DocInfo?docid=`1` &field=`email-fb`]]`
		&thankyou=`orderThank`
		&vericode=`1`
		&eFormOnBeforeFormMerge=`setReCaptcha`
		&eFormOnValidate=`verifyReCaptcha` !]</code>
снипет создан коды вставлены. в чанке формы поле для стандартной капчи удалено и вставлен плейсхолдер [+ReCaptcha+]. и да рекапча не отображается
Комментарий отредактирован 2018-01-29 21:34:00 пользователем tinik
avatar
В последней версии сборки вылетает после отправки формы:

Fatal error: Call to undefined function verifyReCaptcha() in ....public_html/assets/snippets/eform/eform.inc.php on line 277
avatar
я новичок, и не совсем ясны пункты 5 и 6 (можно п6 пошагово??).
Если у меня eform, правильно ли я вставил [+ReCaptcha+]?:

<h4>Получить консультацию</h4>
<div style="margin-left:15px; color:red;">[+validationmessage+]</div>
<form id="questionFormY"  name="questionFormY" method="post" action="[~[*id*]~]">
		<input value="" name="special" class="special" type="text" eform="Спец:date:0"  style="display:none;">
		<input id="name" type="text" name="name" eform="Ваше имя::1" placeholder="Ваше имя*" />
	  	<input id="phone" type="text" name="phone" placeholder="Номер телефона*"  eform="Телефон::1"/>
		
		<input id="equipment" type="text" name="equipment" value="[!getGet? &var=`title`!]" placeholder="[!getGet? &var=`title`!]" style="display: none;" />
[[ip]]
		[+ReCaptcha+]
		<input name="submit" type="submit" id="submit" class="button" value="Получить консультацию">
		<div class="clear"></div>
	
	</form>
Комментарий отредактирован 2019-11-03 13:11:16 пользователем studying_user
avatar
Никто вам не ответит, потому что никто давно не пользуется eform
Вызов eform должен начинаться так
<script src='https://www.google.com/recaptcha/api.js'></script>
[!ReCaptcha!]
[!eForm? 
  &eFormOnValidate=`ReCaptcha`
  &eFormOnBeforeFormMerge=`ReCaptchaDiv`
  &vericode=`0`
...

конец tpl:

...
[+reCaptcha+]
<input type="submit"...

Сниппет ReCaptcha

<?php

//вставить свои:
define('SITEKEY', '');
define ('SECRET', '');

function ReCaptchaDiv(&$fields)
{
$fields['reCaptcha'] = '<div class="g-recaptcha" id="g-recaptcha" data-sitekey="'.SITEKEY.'"></div>';
return $fields;
}
	
if (function_exists('ReCaptcha')) return;

function getCurlData($url)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_TIMEOUT, 10);
    curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16");
    $curlData = curl_exec($curl);
    curl_close($curl);
    return $curlData;
}


function ReCaptcha(&$fields, &$vMsg, &$rMsg) {
    global $modx;	
	session_start();
    $recaptcha=$_POST['g-recaptcha-response'];
    if(!empty($recaptcha))
    {
        
        $google_url="https://www.google.com/recaptcha/api/siteverify";        
        $ip=$_SERVER['REMOTE_ADDR'];
        $url=$google_url."?secret=".SECRET."&response=".$recaptcha."&remoteip=".$ip;
        $res=getCurlData($url);
        $res= json_decode($res, true);
        if(!$res['success'])  $vMsg[3] = 'Вы не подтвердили, что вы не робот!';       

    }
    else $vMsg[3] = 'Вы не подтвердили, что вы не робот!';
	return $vMsg;
}


Вроде работает так. Насколько я помню, была необходимость вынести скрипт в тело страницы, не помню, почему. Ну и сниппет совсем другой сам по себе
avatar
У меня eForm выглядит так:

<?php
/**
 * eForm
 *
 * Robust form parser/processor with validation, multiple sending options, chunk/page support for forms and reports, and file uploads
 *
 * @category   snippet
 * @version    1.4.7
 * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License (GPL)
 * @internal   @properties
 * @internal   @modx_category Forms
 * @internal   @installset base, sample
 * @documentation MODX Docs https://rtfm.modx.com/extras/evo/eform
 * @documentation History, usage and examples [+site_url+]assets/snippets/eform/docs/eform.htm
 * @reportissues https://github.com/modxcms/evolution
 * @author      Original created by Raymond Irving 15-Dec-2004.
 * @author      v1.3+ extended by Jelle Jager (TobyL) September 2006
 * @author      Captcha image support - thanks to Djamoer
 * @author      Multi checkbox, radio, select support - thanks to Djamoer
 * @author      Form Parser and extended validation - by Jelle Jager
 * @author      and many others
 * @lastupdate  11/04/2016
 */
if(!defined('MODX_BASE_PATH')){die('What are you doing? Get out of here!');}

# Set Snippet Paths
$snipFolder = isset($snipFolder)?$snipFolder:'eform';
$snipPath = $modx->config["base_path"].'assets/snippets/'.$snipFolder.'/';


# check if inside manager
if ($modx->isBackend()) {
return ''; # don't go any further when inside manager
}

//tidying up some casing errors in parameters
if(isset($eformOnValidate)) $eFormOnValidate = $eformOnValidate;
if(isset($eformOnBeforeMailSent)) $eFormOnBeforeMailSent = $eformOnBeforeMailSent;
if(isset($eformOnMailSent)) $eFormOnMailSent = $eformOnMailSent;
if(isset($eformOnValidate)) $eFormOnValidate = $eformOnValidate;
if(isset($eformOnBeforeFormMerge)) $eFormOnBeforeFormMerge = $eformOnBeforeFormMerge;
if(isset($eformOnBeforeFormParse)) $eFormOnBeforeFormParse = $eformOnBeforeFormParse;
//for sottwell :)
if(isset($eFormCSS)) $cssStyle = $eFormCSS;

# Snippet customize settings
$_params = array (
   // Snippet Path
   'snipPath' => $snipPath, //includes $snipFolder
	 'snipFolder' => $snipFolder,

// eForm Params
   'vericode' => isset($vericode)? $vericode:"",
   'formid' => isset($formid)? $formid:"",
   'from' => isset($from)? $from:$modx->config['emailsender'],
   'fromname' => isset($fromname)? $fromname:$modx->config['site_name'],
   'to' => isset($to)? $to:$modx->config['emailsender'],
   'cc' => isset($cc)? $cc:"",
   'bcc' => isset($bcc)? $bcc:"",
   'subject' => isset($subject)? $subject:"",
   'ccsender' => isset($ccsender)?$ccsender:0,
   'sendirect' => isset($sendirect)? $sendirect:0,
   'mselector' => isset($mailselector)? $mailselector:0,
   'mobile' => isset($mobile)? $mobile:'',
   'mobiletext' => isset($mobiletext)? $mobiletext:'',
   'autosender' => isset($autosender)? $autosender:$from,
   'autotext' => isset($automessage)? $automessage:"",
   'category' => isset($category)? $category:0,
   'keywords' => isset($keywords)? $keywords:"",
   'gid' => isset($gotoid)? $gotoid:$modx->documentIdentifier,
   'noemail' => isset($noemail)? ($noemail):false,
   'saveform' => isset($saveform)? ($saveform? true:false):true,
   'tpl' => isset($tpl)? $tpl:"",
   'report' => isset($report)? $report:"",
   'allowhtml' => isset($allowhtml)? $allowhtml:0,
   //Added by JJ
   'replyto' => isset($replyto)? $replyto:"",
   'language' => isset($language)? $language:$modx->config['manager_language'],
   'thankyou' => isset($thankyou)? $thankyou:"",
   'isDebug' => isset($debug)? $debug:0,
   'reportAbuse' => isset($reportAbuse)? $reportAbuse:false,
   'disclaimer' => isset($disclaimer)?$disclaimer:'',
   'sendAsHtml' => isset($sendAsHtml)?$sendAsHtml:false,
   'sendAsText' => isset($sendAsText)?$sendAsText:false,
   'sessionVars' => isset($sessionVars)?$sessionVars:false,
   'postOverides' => isset($postOverides)?$postOverides:0,
   'eFormOnBeforeMailSent' => isset($eFormOnBeforeMailSent)?$eFormOnBeforeMailSent:'',
   'eFormOnMailSent' => isset($eFormOnMailSent)?$eFormOnMailSent:'',
   'eFormOnValidate' => isset($eFormOnValidate)?$eFormOnValidate:'',
   'eFormOnBeforeFormMerge' => isset($eFormOnBeforeFormMerge)?$eFormOnBeforeFormMerge:'',
   'eFormOnBeforeFormParse' => isset($eFormOnBeforeFormParse)?$eFormOnBeforeFormParse:'',
   'cssStyle' => isset($cssStyle)?$cssStyle:'',
   'jScript' => isset($jScript)?$jScript:'',
   'submitLimit' => (isset($submitLimit) &&  is_numeric($submitLimit))?$submitLimit*60:0,
   'protectSubmit' => isset($protectSubmit)?$protectSubmit:1,
   'requiredClass' => isset($requiredClass)?$requiredClass:"required",
   'invalidClass' => isset($invalidClass)?$invalidClass:"invalid",
   'runSnippet' => ( isset($runSnippet) && !is_numeric($runSnippet) )?$runSnippet:'',
   'autoSenderName' => isset($autoSenderName)?$autoSenderName:'',
   'attachmentField' => isset($attachmentField)?$attachmentField:'',
   'attachmentPath' => isset($attachmentPath)?$attachmentPath:'',
   'errorTpl' => isset($errorTpl)?$errorTpl:'<div class="errors"><strong>[+ef_message_text+]</strong><br />[+ef_wrapper+]</div>',
   'errorRequiredTpl' => isset($errorRequiredTpl)?$errorRequiredTpl:'<span class="requiredlist"><span>[+ef_required_list+]</span>.</span>',
   'errorRequiredSeparator' => isset($errorRequiredSeparator)?$errorRequiredSeparator:'</span>, <span>',
   'version' => '1.4.6'
);

// pixelchutes PHx workaround
foreach( $_params as $key=>$val ) $params[ $key ] = str_replace( array('((','))'), array('[+','+]'), $val );

# Start processing

include_once ($snipPath."eform.inc.php");

$output = eForm($modx,array_merge($_params,$params));

# Return
return $output;
?>
?>
?>



Если вставляю
<script src='https://www.google.com/recaptcha/api.js'></script>
[!ReCaptcha!]
[!eForm? 
  &eFormOnValidate=`ReCaptcha`
  &eFormOnBeforeFormMerge=`ReCaptchaDiv`
  &vericode=`0`


в // eForm Params — ничего не меняется!
avatar
А зачем мне знать, как у вас выглядит eForm?
Если я вам привел ДРУГОЙ сниппет Recaptcha
avatar
Не надо ничего вставлять в eForm Params. Надо вставлять в вызов сниппета eform
avatar
так я добавляю в сниппет и там:

<?php
/**
 * eForm
 *
 * Robust form parser/processor with validation, multiple sending options, chunk/page support for forms and reports, and file uploads
 *
 * @category   snippet
 * @version    1.4.7
 * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License (GPL)
 * @internal   @properties
 * @internal   @modx_category Forms
 * @internal   @installset base, sample
 * @documentation MODX Docs https://rtfm.modx.com/extras/evo/eform
 * @documentation History, usage and examples [+site_url+]assets/snippets/eform/docs/eform.htm
 * @reportissues https://github.com/modxcms/evolution
 * @author      Original created by Raymond Irving 15-Dec-2004.
 * @author      v1.3+ extended by Jelle Jager (TobyL) September 2006
 * @author      Captcha image support - thanks to Djamoer
 * @author      Multi checkbox, radio, select support - thanks to Djamoer
 * @author      Form Parser and extended validation - by Jelle Jager
 * @author      and many others
 * @lastupdate  11/04/2016
 */
if(!defined('MODX_BASE_PATH')){die('What are you doing? Get out of here!');}

# Set Snippet Paths
$snipFolder = isset($snipFolder)?$snipFolder:'eform';
$snipPath = $modx->config["base_path"].'assets/snippets/'.$snipFolder.'/';


# check if inside manager

и далее парпаметры и тд
avatar
Не надо добавлять в сниппет
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.