PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.9.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.9.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / fields / FrmFieldCaptcha.php

FrmFieldCaptcha.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.9.1, at classes/models/fields/FrmFieldCaptcha.php

405 lines 9.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 /**
7 * @since 3.0
8 */
9 class FrmFieldCaptcha extends FrmFieldType {
10
11 /**
12 * @var string
13 * @since 3.0
14 */
15 protected $type = 'captcha';
16
17 /**
18 * @return string
19 */
20 protected function include_form_builder_file() {
21 return FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/field-captcha.php';
22 }
23
24 /**
25 * Returns the image name for a captcha.
26 *
27 * @return string
28 */
29 public static function get_captcha_image_name() {
30 $frm_settings = FrmAppHelper::get_settings();
31 $active_captcha = $frm_settings->active_captcha;
32 if ( $active_captcha === 'recaptcha' && $frm_settings->re_type === 'v3' ) {
33 $image_name = 'recaptcha_v3';
34 } else {
35 $image_name = $active_captcha;
36 }
37
38 return $image_name;
39 }
40
41 /**
42 * @return array
43 */
44 protected function field_settings_for_type() {
45 $settings = FrmCaptchaFactory::get_settings_object();
46 return array(
47 'required' => false,
48 'invalid' => true,
49 'captcha_size' => $settings->should_show_captcha_size(),
50 'captcha_theme' => $settings->should_show_captcha_theme(),
51 'captcha_theme_auto_option' => $settings->should_show_captcha_theme_auto_option(),
52 'default' => false,
53 );
54 }
55
56 /**
57 * @return array
58 */
59 protected function new_field_settings() {
60 $frm_settings = FrmAppHelper::get_settings();
61
62 return array(
63 'invalid' => $frm_settings->re_msg,
64 );
65 }
66
67 /**
68 * @return array
69 */
70 protected function extra_field_opts() {
71 return array(
72 'label' => 'none',
73 'captcha_size' => 'normal',
74 'captcha_theme' => 'light',
75 );
76 }
77
78 /**
79 * Remove the "for" attribute for captcha
80 *
81 * @param array $args
82 * @param string $html
83 *
84 * @return string
85 */
86 protected function before_replace_html_shortcodes( $args, $html ) {
87 $frm_settings = FrmAppHelper::get_settings();
88 $replace_response = $frm_settings->active_captcha === 'recaptcha' ? 'g-recaptcha-response' : 'h-captcha-response';
89 $replaced_for = str_replace( ' for="field_[key]"', ' for="' . $replace_response . '"', $html );
90
91 return $replaced_for;
92 }
93
94 /**
95 * @param array $args
96 * @param array $shortcode_atts
97 * @return string
98 */
99 public function front_field_input( $args, $shortcode_atts ) {
100 $frm_settings = FrmAppHelper::get_settings();
101 if ( ! self::should_show_captcha() ) {
102 return '';
103 }
104
105 $settings = FrmCaptchaFactory::get_settings_object();
106 $div_attributes = array(
107 'id' => $args['html_id'],
108 'class' => $this->class_prefix( $frm_settings ) . $this->captcha_class( $frm_settings ),
109 'data-sitekey' => $settings->get_pubkey(),
110 );
111 $div_attributes = $settings->add_front_end_element_attributes( $div_attributes, $this->field );
112 $html = '<div ' . FrmAppHelper::array_to_html_params( $div_attributes ) . '></div>';
113
114 return $html;
115 }
116
117 /**
118 * @return void
119 */
120 protected function load_field_scripts( $args ) {
121 $api_js_url = $this->api_url();
122
123 wp_register_script( 'captcha-api', $api_js_url, array( 'formidable' ), '3', true );
124 wp_enqueue_script( 'captcha-api' );
125 }
126
127 /**
128 * Get the URL for the script JS that is loaded on the front end.
129 *
130 * @return string
131 */
132 protected function api_url() {
133 $frm_settings = FrmAppHelper::get_settings();
134 $active_mode = $frm_settings->active_captcha;
135
136 if ( 'recaptcha' === $active_mode ) {
137 return $this->recaptcha_api_url( $frm_settings );
138 }
139
140 if ( 'hcaptcha' === $active_mode ) {
141 return $this->hcaptcha_api_url();
142 }
143
144 return $this->turnstile_api_url();
145 }
146
147 /**
148 * @param FrmSettings $frm_settings
149 * @return string
150 */
151 protected function recaptcha_api_url( $frm_settings ) {
152 $api_js_url = 'https://www.google.com/recaptcha/api.js?';
153
154 $allow_mutiple = $frm_settings->re_multi;
155 if ( $allow_mutiple ) {
156 $api_js_url .= '&onload=frmRecaptcha&render=explicit';
157 }
158
159 $lang = apply_filters( 'frm_recaptcha_lang', $frm_settings->re_lang, $this->field );
160 if ( $lang ) {
161 $api_js_url .= '&hl=' . $lang;
162 }
163
164 /**
165 * @param string $api_js_url
166 */
167 $api_js_url = apply_filters( 'frm_recaptcha_js_url', $api_js_url );
168
169 return $api_js_url;
170 }
171
172 /**
173 * @since 6.0
174 *
175 * @return string
176 */
177 protected function hcaptcha_api_url() {
178 $api_js_url = 'https://js.hcaptcha.com/1/api.js';
179
180 /**
181 * Allows updating hcaptcha js api url.
182 *
183 * @since 6.0
184 *
185 * @param string $api_js_url
186 */
187 $api_js_url = apply_filters( 'frm_hcaptcha_js_url', $api_js_url );
188
189 return $api_js_url;
190 }
191
192 /**
193 * @since 6.8.4
194 *
195 * @return string
196 */
197 protected function turnstile_api_url() {
198 $api_js_url = 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=frmTurnstile';
199
200 /**
201 * Allows updating hcaptcha js api url.
202 *
203 * @since 6.8.4
204 *
205 * @param string $api_js_url
206 */
207 $api_js_url = apply_filters( 'frm_turnstile_js_url', $api_js_url );
208
209 return $api_js_url;
210 }
211
212 /**
213 * @param FrmSettings $frm_settings
214 *
215 * @return string
216 *
217 * @psalm-return ''|'frm-'
218 */
219 protected function class_prefix( $frm_settings ) {
220 if ( $this->allow_multiple( $frm_settings ) && $frm_settings->active_captcha === 'recaptcha' ) {
221 $class_prefix = 'frm-';
222 } else {
223 $class_prefix = '';
224 }
225
226 return $class_prefix;
227 }
228
229 /**
230 * @param FrmSettings $frm_settings
231 *
232 * @return string
233 *
234 * @psalm-return 'g-recaptcha'|'h-captcha'
235 */
236 protected function captcha_class( $frm_settings ) {
237 $settings = FrmCaptchaFactory::get_settings_object();
238 return $settings->get_element_class_name();
239 }
240
241 protected function allow_multiple( $frm_settings ) {
242 return $frm_settings->re_multi;
243 }
244
245 /**
246 * @since 4.07
247 * @param array $args
248 * @return array
249 */
250 protected function validate_against_api( $args ) {
251 $errors = array();
252 $frm_settings = FrmAppHelper::get_settings();
253 $resp = $this->send_api_check( $frm_settings );
254 $response = json_decode( wp_remote_retrieve_body( $resp ), true );
255
256 if ( is_wp_error( $resp ) ) {
257 $error_string = $resp->get_error_message();
258 $errors[ 'field' . $args['id'] ] = __( 'There was a problem verifying your captcha', 'formidable' );
259 $errors[ 'field' . $args['id'] ] .= ' ' . $error_string;
260 return $errors;
261 }
262
263 if ( ! is_array( $response ) ) {
264 return $errors;
265 }
266
267 if ( $frm_settings->active_captcha === 'recaptcha' ) {
268 if ( 'v3' === $frm_settings->re_type && array_key_exists( 'score', $response ) ) {
269 $threshold = floatval( $frm_settings->re_threshold );
270 $score = floatval( $response['score'] );
271
272 $this->set_score( $score );
273
274 if ( $score < $threshold ) {
275 $response['success'] = false;
276 }
277 }
278 }
279
280 if ( isset( $response['success'] ) && ! $response['success'] ) {
281 // What happens when the CAPTCHA was entered incorrectly
282 $invalid_message = FrmField::get_option( $this->field, 'invalid' );
283 if ( $invalid_message === __( 'The reCAPTCHA was not entered correctly', 'formidable' ) ) {
284 $invalid_message = '';
285 }
286 $errors[ 'field' . $args['id'] ] = ( $invalid_message === '' ? $frm_settings->re_msg : $invalid_message );
287 }
288
289 return $errors;
290 }
291
292 /**
293 * @param float $score
294 * @return void
295 */
296 private function set_score( $score ) {
297 global $frm_vars;
298 if ( ! isset( $frm_vars['captcha_scores'] ) ) {
299 $frm_vars['captcha_scores'] = array();
300 }
301 $form_id = is_object( $this->field ) ? $this->field->form_id : $this->field['form_id'];
302 if ( ! isset( $frm_vars['captcha_scores'][ $form_id ] ) ) {
303 $frm_vars['captcha_scores'][ $form_id ] = $score;
304 }
305 }
306
307 /**
308 * @param array $args
309 * @return array
310 */
311 public function validate( $args ) {
312 if ( ! $this->should_validate() ) {
313 return array();
314 }
315
316 $missing_token = ! self::post_data_includes_token();
317 if ( $missing_token ) {
318 return array( 'field' . $args['id'] => __( 'The captcha is missing from this form', 'formidable' ) );
319 }
320
321 return $this->validate_against_api( $args );
322 }
323
324 /**
325 * @since 6.8.4
326 *
327 * @return bool
328 */
329 protected static function post_data_includes_token() {
330 $settings = FrmCaptchaFactory::get_settings_object();
331 // phpcs:ignore WordPress.Security.NonceVerification.Missing
332 return ! empty( $_POST[ $settings->token_field ] );
333 }
334
335 /**
336 * Check if the active captcha type's public key is set.
337 *
338 * @since 4.07
339 *
340 * @return bool
341 */
342 public static function should_show_captcha() {
343 $settings = FrmCaptchaFactory::get_settings_object();
344 return $settings->has_pubkey();
345 }
346
347 /**
348 * @return bool
349 */
350 protected function should_validate() {
351 $is_hidden_field = apply_filters( 'frm_is_field_hidden', false, $this->field, wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
352 if ( FrmAppHelper::is_admin() || $is_hidden_field ) {
353 return false;
354 }
355
356 // don't require the captcha if it shouldn't be shown
357 return self::should_show_captcha();
358 }
359
360 /**
361 * @param FrmSettings $frm_settings
362 */
363 protected function send_api_check( $frm_settings ) {
364 $captcha_settings = FrmCaptchaFactory::get_settings_object();
365 $arg_array = array(
366 'body' => array(
367 'secret' => $captcha_settings->secret,
368 'response' => FrmAppHelper::get_param( $captcha_settings->token_field, '', 'post', 'sanitize_text_field' ),
369 'remoteip' => FrmAppHelper::get_ip_address(),
370 ),
371 );
372
373 return wp_remote_post( $captcha_settings->endpoint, $arg_array );
374 }
375
376 /**
377 * Updates field name in page builder to the currently activated captcha if it is set to the default.
378 *
379 * @since 6.0
380 *
381 * @param array $values
382 *
383 * @return array $values
384 */
385 public static function update_field_name( $values ) {
386 if ( $values['type'] === 'captcha' ) {
387 $name = $values['name'];
388 if ( in_array( $name, array( __( 'reCAPTCHA', 'formidable' ), __( 'hCaptcha', 'formidable' ) ), true ) ) {
389 $values['name'] = __( 'Captcha', 'formidable' );
390 }
391 }
392
393 return $values;
394 }
395
396 /**
397 * @param FrmSettings $frm_settings
398 * @return string
399 */
400 protected function captcha_size( $frm_settings ) {
401 _deprecated_function( __METHOD__, '6.8.4' );
402 return 'normal';
403 }
404 }
405