Completed
Push — master ( ca2209...0f254b )
by Michael
01:02
created

src/Forms/HCaptchaField.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace X3dgoo\HCaptcha\Forms;
4
5
use Psr\Log\LoggerInterface;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\Forms\FormField;
9
use SilverStripe\Forms\Validator;
10
use SilverStripe\ORM\FieldType\DBHTMLText;
11
use SilverStripe\View\Requirements;
12
13
class HCaptchaField extends FormField
14
{
15
    /**
16
     * HCaptcha Site Key
17
     * @config HCaptchaField.site_key
18
     */
19
    private static $site_key;
20
21
    /**
22
     * HCaptcha Secret Key
23
     * @config HCaptchaField.secret_key
24
     */
25
    private static $secret_key;
26
27
    /**
28
     * HCaptcha Site Key
29
     * Configurable via Injector config
30
     */
31
    protected $_siteKey;
32
33
    /**
34
     * HCaptcha Site Key
35
     * Configurable via Injector config
36
     */
37
    protected $_secretKey;
38
39
    /**
40
     * Creates a new HCaptcha field.
41
     * @param string $name The internal field name, passed to forms.
42
     * @param string $title The human-readable field label.
43
     * @param mixed $value The value of the field (unused)
44
     */
45
    public function __construct($name, $title = null, $value = null)
46
    {
47
        parent::__construct($name, $title, $value);
48
49
        $this->title = $title;
50
    }
51
52
    /**
53
     * Adds in the requirements for the field
54
     * @param array $properties Array of properties for the form element (not used)
55
     * @return DBHTMLText Rendered field template
56
     */
57
    public function Field($properties = [])
58
    {
59
        $siteKey = $this->getSiteKey();
60
        $secretKey = $this->_secretKey ? $this->_secretKey : self::config()->secret_key;
61
62
        if (empty($siteKey) || empty($secretKey)) {
63
            user_error(
64
                'You must configure HCaptchaField.site_key and HCaptchaField.secret_key. ' .
65
                    'You can retrieve these at https://hcaptcha.com',
66
                E_USER_ERROR
67
            );
68
        }
69
70
        Requirements::javascript('https://hcaptcha.com/1/api.js');
71
72
        return parent::Field($properties);
73
    }
74
75
    /**
76
     * Validates the captcha against the hCaptcha API
77
     * @param Validator $validator Validator to send errors to
78
     * @return bool Returns boolean true if valid false if not
79
     */
80
    public function validate($validator)
81
    {
82
        $hCaptchaResponse = Controller::curr()->getRequest()->requestVar('h-captcha-response');
83
84
        if (!isset($hCaptchaResponse)) {
85
            $validator->validationError(
86
                $this->name,
87
                _t(
88
                    'X3dgoo\\HCaptcha\\Forms\\HCaptchaField.EMPTY',
89
                    'Please answer the captcha. If you do not see the captcha please enable Javascript'
90
                ),
91
                'validation'
92
            );
93
94
            return false;
95
        }
96
97
        if (!function_exists('curl_init')) {
98
            user_error('You must enable php-curl to use this field', E_USER_ERROR);
99
100
            return false;
101
        }
102
103
        $secret_key = $this->_secretKey ?: self::config()->secret_key;
104
        $url = 'https://hcaptcha.com/siteverify' .
105
            '?secret=' . $secret_key .
106
            '&response=' . rawurlencode($hCaptchaResponse) .
107
            '&remoteip=' . rawurlencode($_SERVER['REMOTE_ADDR']);
108
        $ch = curl_init($url);
109
110
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
111
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
112
        curl_setopt($ch, CURLOPT_USERAGENT, str_replace(',', '/', 'SilverStripe'));
113
        $response = json_decode(curl_exec($ch), true);
114
115
        if (is_array($response)) {
116
            if (array_key_exists('success', $response) && $response['success'] == false) {
117
                $validator->validationError(
118
                    $this->name,
119
                    _t(
120
                        'X3dgoo\\HCaptcha\\Forms\\HCaptchaField.EMPTY',
121
                        'Please answer the captcha. If you do not see the captcha please enable Javascript'
122
                    ),
123
                    'validation'
124
                );
125
126
                return false;
127
            }
128
        } else {
129
            $validator->validationError(
130
                $this->name,
131
                _t(
132
                    'X3dgoo\\HCaptcha\\Forms\\HCaptchaField.VALIDATE_ERROR',
133
                    'Captcha could not be validated'
134
                ),
135
                'validation'
136
            );
137
            $logger = Injector::inst()->get(LoggerInterface::class);
138
            $logger->error(
139
                'Captcha validation failed as request was not successful.'
140
            );
141
142
            return false;
143
        }
144
145
        return true;
146
    }
147
148
    /**
149
     * Gets the site key configured via HCaptchaField.site_key this is used in the template
150
     * @return string
151
     */
152
    public function getSiteKey()
153
    {
154
        return $this->_sitekey ? $this->_sitekey : self::config()->site_key;
0 ignored issues
show
The property _sitekey does not seem to exist. Did you mean _siteKey?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
155
    }
156
157
    /**
158
     * Setter for _siteKey to allow injector config to override the value
159
     * @param string $key
160
     */
161
    public function setSiteKey($key)
162
    {
163
        $this->_sitekey = $key;
0 ignored issues
show
The property _sitekey does not seem to exist. Did you mean _siteKey?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
164
    }
165
166
    /**
167
     * Setter for _secretKey to allow injector config to override the value
168
     * @param string $key
169
     */
170
    public function setSecretKey($key)
171
    {
172
        $this->_secretKey = $key;
173
    }
174
175
    /**
176
     * Gets the form's id
177
     * @return string
178
     */
179
    public function getFormID()
180
    {
181
        return ($this->form ? $this->getTemplateHelper()->generateFormID($this->form) : null);
182
    }
183
}
184