/
JavascriptCaptcha.php
108 lines (89 loc) · 3.42 KB
/
JavascriptCaptcha.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?php
/**
* @link https://sprout.barrelstrengthdesign.com
* @copyright Copyright (c) Barrel Strength Design LLC
* @license https://craftcms.github.io/license
*/
namespace barrelstrength\sproutforms\captchas;
use barrelstrength\sproutforms\base\Captcha;
use barrelstrength\sproutforms\events\OnBeforeValidateEntryEvent;
use Craft;
use craft\errors\MissingComponentException;
use craft\helpers\StringHelper;
use craft\web\View;
use yii\base\InvalidConfigException;
/**
* Class InvisibleCaptcha
*
* @property string $name
* @property string $description
* @property string $captchaHtml
*/
class JavascriptCaptcha extends Captcha
{
const JAVASCRIPT_CAPTCHA_INPUT_KEY = 'sprout-forms-jck';
const JAVASCRIPT_CAPTCHA_VALUE_PREFIX = 'sprout-forms-jcv';
/**
* @inheritdoc
*/
public function getName(): string
{
return 'Javascript Captcha';
}
/**
* @inheritdoc
*/
public function getDescription(): string
{
return Craft::t('sprout-forms', 'Prevent a form from being submmitted if a user does not have JavaScript enabled');
}
/**
* @inheritdoc
* @throws MissingComponentException
*/
public function getCaptchaHtml(): string
{
$inputName = StringHelper::appendUniqueIdentifier(self::JAVASCRIPT_CAPTCHA_INPUT_KEY);
$inputValue = StringHelper::appendUniqueIdentifier(self::JAVASCRIPT_CAPTCHA_VALUE_PREFIX);
// Create session variable to retrieve a given forms js key/value
Craft::$app->getSession()->set($inputName, $inputValue);
// Create a second session variable so we can match the posted key
// to what we expect it to be. If we can retrieve this second key
// based on the submitted value, we know it's the same. And this lets
// us support more than one form on a page.
Craft::$app->getSession()->set($inputValue, true);
// Set a hidden field with no value
$output = '<input type="hidden" id="'.$inputName.'" name="'.$inputName.'" />';
// Set the value of the hidden field using js
$js = '(function(){ document.getElementById("'.$inputName.'").value = "'.$inputValue.'"; })();';
Craft::$app->getView()->registerJs($js, View::POS_END);
return $output;
}
/**
* @param OnBeforeValidateEntryEvent $event
*
* @return bool
* @throws MissingComponentException
* @throws InvalidConfigException
*/
public function verifySubmission(OnBeforeValidateEntryEvent $event): bool
{
$postedValues = Craft::$app->getRequest()->getBodyParams();
// Filter out the posted JS Captcha Input.
$jsCaptchaPostedInput = array_filter($postedValues, static function($key) {
return strpos($key, self::JAVASCRIPT_CAPTCHA_INPUT_KEY) === 0;
}, ARRAY_FILTER_USE_KEY);
$inputValue = reset($jsCaptchaPostedInput);
$inputKey = key($jsCaptchaPostedInput);
if (Craft::$app->getSession()->get($inputValue) !== true) {
$errorMessage = 'Javascript not enabled in browser or form page does not have a <body> tag.';
Craft::error($errorMessage, __METHOD__);
$this->addError(self::CAPTCHA_ERRORS_KEY, $errorMessage);
return false;
}
// If there is a valid unique token set, unset it
Craft::$app->getSession()->remove($inputKey);
Craft::$app->getSession()->remove($inputValue);
return true;
}
}