PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.4
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.4
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.4, at classes/models/fields/FrmFieldCaptcha.php

365 lines 9.3 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 return array(
46 'required' => false,
47 'invalid' => true,
48 'captcha_size' => true,
49 'default' => false,
50 );
51 }
52
53 /**
54 * @return array
55 */
56 protected function new_field_settings() {
57 $frm_settings = FrmAppHelper::get_settings();
58
59 return array(
60 'invalid' => $frm_settings->re_msg,
61 );
62 }
63
64 /**
65 * @return array
66 */
67 protected function extra_field_opts() {
68 return array(
69 'label' => 'none',
70 'captcha_size' => 'normal',
71 'captcha_theme' => 'light',
72 );
73 }
74
75 /**
76 * Remove the "for" attribute for captcha
77 *
78 * @param array $args
79 * @param string $html
80 *
81 * @return string
82 */
83 protected function before_replace_html_shortcodes( $args, $html ) {
84 $frm_settings = FrmAppHelper::get_settings();
85 $replace_response = $frm_settings->active_captcha === 'recaptcha' ? 'g-recaptcha-response' : 'h-captcha-response';
86 $replaced_for = str_replace( ' for="field_[key]"', ' for="' . $replace_response . '"', $html );
87
88 return $replaced_for;
89 }
90
91 /**
92 * @return string
93 */
94 public function front_field_input( $args, $shortcode_atts ) {
95 $frm_settings = FrmAppHelper::get_settings();
96 if ( ! self::should_show_captcha() ) {
97 return '';
98 }
99
100 $class_prefix = $this->class_prefix( $frm_settings );
101 $captcha_class = $this->captcha_class( $frm_settings );
102 $captcha_size = $this->captcha_size( $frm_settings );
103 $allow_mutiple = $frm_settings->re_multi;
104
105 if ( $frm_settings->active_captcha === 'recaptcha' ) {
106 $site_key = $frm_settings->pubkey;
107 $recaptcha_options = ' data-size="' . esc_attr( $captcha_size ) . '" data-theme="' . esc_attr( $this->field['captcha_theme'] ) . '"';
108 } else {
109 $site_key = $frm_settings->hcaptcha_pubkey;
110 }
111
112 $html = '<div id="' . esc_attr( $args['html_id'] ) . '" class="' . esc_attr( $class_prefix ) . $captcha_class . '" data-sitekey="' . esc_attr( $site_key ) . '"';
113 $html .= ! empty( $recaptcha_options ) ? $recaptcha_options : '';
114 if ( $captcha_size === 'invisible' && ! $allow_mutiple ) {
115 $html .= ' data-callback="frmAfterRecaptcha"';
116 }
117 $html .= '></div>';
118
119 return $html;
120 }
121
122 /**
123 * @return void
124 */
125 protected function load_field_scripts( $args ) {
126 $api_js_url = $this->api_url();
127
128 wp_register_script( 'captcha-api', $api_js_url, array( 'formidable' ), '3', true );
129 wp_enqueue_script( 'captcha-api' );
130 }
131
132 protected function api_url() {
133 $frm_settings = FrmAppHelper::get_settings();
134 if ( $frm_settings->active_captcha === 'recaptcha' ) {
135 return $this->recaptcha_api_url( $frm_settings );
136 }
137
138 return $this->hcaptcha_api_url();
139 }
140
141 /**
142 * @param FrmSettings $frm_settings
143 */
144 protected function recaptcha_api_url( $frm_settings ) {
145 $api_js_url = 'https://www.google.com/recaptcha/api.js?';
146
147 $allow_mutiple = $frm_settings->re_multi;
148 if ( $allow_mutiple ) {
149 $api_js_url .= '&onload=frmRecaptcha&render=explicit';
150 }
151
152 $lang = apply_filters( 'frm_recaptcha_lang', $frm_settings->re_lang, $this->field );
153 if ( ! empty( $lang ) ) {
154 $api_js_url .= '&hl=' . $lang;
155 }
156
157 $api_js_url = apply_filters( 'frm_recaptcha_js_url', $api_js_url );
158
159 return $api_js_url;
160 }
161
162 protected function hcaptcha_api_url() {
163 $api_js_url = 'https://js.hcaptcha.com/1/api.js';
164
165 /**
166 * Allows updating hcaptcha js api url.
167 *
168 * @since 6.0
169 *
170 * @param string $api_js_url
171 */
172 $api_js_url = apply_filters( 'frm_hcaptcha_js_url', $api_js_url );
173
174 return $api_js_url;
175 }
176
177 /**
178 * @param FrmSettings $frm_settings
179 *
180 * @return string
181 *
182 * @psalm-return ''|'frm-'
183 */
184 protected function class_prefix( $frm_settings ) {
185 if ( $this->allow_multiple( $frm_settings ) && $frm_settings->active_captcha === 'recaptcha' ) {
186 $class_prefix = 'frm-';
187 } else {
188 $class_prefix = '';
189 }
190
191 return $class_prefix;
192 }
193
194 /**
195 * @param FrmSettings $frm_settings
196 *
197 * @return string
198 *
199 * @psalm-return 'g-recaptcha'|'h-captcha'
200 */
201 protected function captcha_class( $frm_settings ) {
202 return $frm_settings->active_captcha === 'recaptcha' ? 'g-recaptcha' : 'h-captcha';
203 }
204
205 protected function allow_multiple( $frm_settings ) {
206 return $frm_settings->re_multi;
207 }
208
209 /**
210 * @return string
211 *
212 * @param FrmSettings $frm_settings
213 */
214 protected function captcha_size( $frm_settings ) {
215 if ( in_array( $frm_settings->re_type, array( 'invisible', 'v3' ), true ) ) {
216 return 'invisible';
217 }
218 // for reverse compatibility
219 return $this->field['captcha_size'] === 'default' ? 'normal' : $this->field['captcha_size'];
220 }
221
222 /**
223 * @since 4.07
224 * @param array $args
225 * @return array
226 */
227 protected function validate_against_api( $args ) {
228 $errors = array();
229 $frm_settings = FrmAppHelper::get_settings();
230 $resp = $this->send_api_check( $frm_settings );
231 $response = json_decode( wp_remote_retrieve_body( $resp ), true );
232
233 if ( is_wp_error( $resp ) ) {
234 $error_string = $resp->get_error_message();
235 $errors[ 'field' . $args['id'] ] = __( 'There was a problem verifying your captcha', 'formidable' );
236 $errors[ 'field' . $args['id'] ] .= ' ' . $error_string;
237 return $errors;
238 }
239
240 if ( ! is_array( $response ) ) {
241 return $errors;
242 }
243
244 if ( $frm_settings->active_captcha === 'recaptcha' ) {
245 if ( 'v3' === $frm_settings->re_type && array_key_exists( 'score', $response ) ) {
246 $threshold = floatval( $frm_settings->re_threshold );
247 $score = floatval( $response['score'] );
248
249 $this->set_score( $score );
250
251 if ( $score < $threshold ) {
252 $response['success'] = false;
253 }
254 }
255 }
256
257 if ( isset( $response['success'] ) && ! $response['success'] ) {
258 // What happens when the CAPTCHA was entered incorrectly
259 $invalid_message = FrmField::get_option( $this->field, 'invalid' );
260 if ( $invalid_message === __( 'The reCAPTCHA was not entered correctly', 'formidable' ) ) {
261 $invalid_message = '';
262 }
263 $errors[ 'field' . $args['id'] ] = ( $invalid_message === '' ? $frm_settings->re_msg : $invalid_message );
264 }
265
266 return $errors;
267 }
268
269 /**
270 * @param float $score
271 * @return void
272 */
273 private function set_score( $score ) {
274 global $frm_vars;
275 if ( ! isset( $frm_vars['captcha_scores'] ) ) {
276 $frm_vars['captcha_scores'] = array();
277 }
278 $form_id = is_object( $this->field ) ? $this->field->form_id : $this->field['form_id'];
279 if ( ! isset( $frm_vars['captcha_scores'][ $form_id ] ) ) {
280 $frm_vars['captcha_scores'][ $form_id ] = $score;
281 }
282 }
283
284 /**
285 * @param array $args
286 * @return array
287 */
288 public function validate( $args ) {
289 if ( ! $this->should_validate() ) {
290 return array();
291 }
292
293 // phpcs:ignore WordPress.Security.NonceVerification.Missing
294 if ( ! isset( $_POST['g-recaptcha-response'] ) && ! isset( $_POST['h-captcha-response'] ) ) {
295 // There was no captcha submitted.
296 return array( 'field' . $args['id'] => __( 'The captcha is missing from this form', 'formidable' ) );
297 }
298
299 return $this->validate_against_api( $args );
300 }
301
302 /**
303 * @since 4.07
304 * @return bool
305 */
306 public static function should_show_captcha() {
307 $frm_settings = FrmAppHelper::get_settings();
308 if ( $frm_settings->active_captcha === 'recaptcha' ) {
309 return ! empty( $frm_settings->pubkey );
310 }
311
312 return ! empty( $frm_settings->hcaptcha_pubkey );
313 }
314
315 /**
316 * @return bool
317 */
318 protected function should_validate() {
319 $is_hidden_field = apply_filters( 'frm_is_field_hidden', false, $this->field, wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
320 if ( FrmAppHelper::is_admin() || $is_hidden_field ) {
321 return false;
322 }
323
324 // don't require the captcha if it shouldn't be shown
325 return self::should_show_captcha();
326 }
327
328 /**
329 * @param FrmSettings $frm_settings
330 */
331 protected function send_api_check( $frm_settings ) {
332 $captcha_settings = new FrmFieldCaptchaSettings( $frm_settings );
333
334 $arg_array = array(
335 'body' => array(
336 'secret' => $captcha_settings->secret,
337 'response' => FrmAppHelper::get_param( $captcha_settings->token_field, '', 'post', 'sanitize_text_field' ),
338 'remoteip' => FrmAppHelper::get_ip_address(),
339 ),
340 );
341
342 return wp_remote_post( $captcha_settings->endpoint, $arg_array );
343 }
344
345 /**
346 * Updates field name in page builder to the currently activated captcha if it is set to the default.
347 *
348 * @since 6.0
349 *
350 * @param array $values
351 *
352 * @return array $values
353 */
354 public static function update_field_name( $values ) {
355 if ( $values['type'] === 'captcha' ) {
356 $name = $values['name'];
357 if ( in_array( $name, array( __( 'reCAPTCHA', 'formidable' ), __( 'hCaptcha', 'formidable' ) ), true ) ) {
358 $values['name'] = __( 'Captcha', 'formidable' );
359 }
360 }
361
362 return $values;
363 }
364 }
365