PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.0.7
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.0.7
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
sureforms / inc / form-submit.php
form-submit.php
840 lines 27.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Sureforms Submit Class file.
4 *
5 * @package sureforms.
6 * @since 0.0.1
7 */
8
9 namespace SRFM\Inc;
10
11 use SRFM\Inc\Database\Tables\Entries;
12 use SRFM\Inc\Email\Email_Template;
13 use SRFM\Inc\Lib\Browser\Browser;
14 use SRFM\Inc\Traits\Get_Instance;
15 use WP_Error;
16 use WP_REST_Server;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // Exit if accessed directly.
20 }
21
22 if ( ! function_exists( 'wp_handle_upload' ) ) {
23 require_once ABSPATH . 'wp-admin/includes/file.php';
24 }
25
26 /**
27 * Sureforms Submit Class.
28 *
29 * @since 0.0.1
30 */
31 class Form_Submit {
32 use Get_Instance;
33
34 /**
35 * Namespace.
36 *
37 * @var string
38 */
39 protected $namespace = 'sureforms/v1';
40
41 /**
42 * Constructor
43 *
44 * @since 0.0.1
45 */
46 public function __construct() {
47 add_action( 'rest_api_init', [ $this, 'register_custom_endpoint' ] );
48 add_action( 'wp_ajax_validation_ajax_action', [ $this, 'field_unique_validation' ] );
49 add_action( 'wp_ajax_nopriv_validation_ajax_action', [ $this, 'field_unique_validation' ] );
50 // for quick action bar.
51 add_action( 'wp_ajax_srfm_global_update_allowed_block', [ $this, 'srfm_global_update_allowed_block' ] );
52 add_action( 'wp_ajax_srfm_global_sidebar_enabled', [ $this, 'srfm_global_sidebar_enabled' ] );
53 }
54
55 /**
56 * Add custom API Route submit-form
57 *
58 * @return void
59 * @since 0.0.1
60 */
61 public function register_custom_endpoint() {
62 register_rest_route(
63 $this->namespace,
64 '/submit-form',
65 [
66 'methods' => WP_REST_Server::EDITABLE,
67 'callback' => [ $this, 'handle_form_submission' ],
68 'permission_callback' => '__return_true',
69 ]
70 );
71 }
72
73 /**
74 * Check whether a given request has permission access route.
75 *
76 * @since 0.0.1
77 * @return WP_Error|bool
78 */
79 public function permissions_check() {
80 if ( ! current_user_can( 'manage_options' ) ) {
81 return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot access this route', 'sureforms' ), [ 'status' => rest_authorization_required_code() ] );
82 }
83 return true;
84 }
85
86 /**
87 * Validate Turnstile token
88 *
89 * @param string $secret_key Turnstile token.
90 * @param string|false $response Response.
91 * @param string|false $remote_ip Remote IP.
92 * @return array<mixed>|mixed Result of the validation.
93 */
94 public static function validate_turnstile_token( $secret_key, $response, $remote_ip ) {
95
96 if ( empty( $secret_key ) || ! is_string( $secret_key ) ) {
97 return [
98 'success' => false,
99 'error' => __( 'Cloudflare Turnstile secret key is invalid.', 'sureforms' ),
100 ];
101 }
102
103 if ( empty( $response ) ) {
104 return [
105 'success' => false,
106 'error' => __( 'Cloudflare Turnstile response is missing.', 'sureforms' ),
107 ];
108 }
109
110 $body = [
111 'secret' => $secret_key,
112 'response' => $response,
113 'remoteip' => $remote_ip,
114 ];
115
116 $url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
117
118 $args = [
119 'body' => $body,
120 'timeout' => 15,
121 ];
122
123 $response = wp_remote_post( $url, $args );
124
125 if ( is_wp_error( $response ) ) {
126 $error_message = $response->get_error_message();
127 return [
128 'success' => false,
129 'error' => $error_message,
130 ];
131 }
132
133 return json_decode( wp_remote_retrieve_body( $response ), true );
134 }
135
136 /**
137 * Validate hCaptcha token
138 *
139 * @param string $secret_key hCaptcha token.
140 * @param string|false $response Response.
141 * @param string|false $remote_ip Remote IP.
142 * @since 0.0.5
143 * @return array<mixed>|mixed Result of the validation.
144 */
145 public static function validate_hcaptcha_token( $secret_key, $response, $remote_ip ) {
146
147 if ( empty( $secret_key ) || ! is_string( $secret_key ) ) {
148 return [
149 'success' => false,
150 'error' => __( 'hCaptcha secret key is invalid.', 'sureforms' ),
151 ];
152 }
153
154 if ( empty( $response ) ) {
155 return [
156 'success' => false,
157 'error' => __( 'hCaptcha response is missing.', 'sureforms' ),
158 ];
159 }
160
161 $body = [
162 'secret' => $secret_key,
163 'response' => $response,
164 'remoteip' => $remote_ip,
165 ];
166
167 $url = 'https://api.hcaptcha.com/siteverify';
168
169 $args = [
170 'body' => $body,
171 'timeout' => 15,
172 ];
173
174 $response = wp_remote_post( $url, $args );
175
176 if ( is_wp_error( $response ) ) {
177 $error_message = $response->get_error_message();
178 return [
179 'success' => false,
180 'error' => $error_message,
181 ];
182 }
183
184 return json_decode( wp_remote_retrieve_body( $response ), true );
185 }
186
187 /**
188 * Handle Form Submission
189 *
190 * @param \WP_REST_Request $request Request object or array containing form data.
191 * @since 0.0.1
192 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
193 */
194 public function handle_form_submission( $request ) {
195
196 $nonce = Helper::get_string_value( $request->get_header( 'X-WP-Nonce' ) );
197
198 if ( ! wp_verify_nonce( sanitize_text_field( $nonce ), 'wp_rest' ) ) {
199 wp_send_json_error(
200 [
201 'data' => __( 'Nonce verification failed.', 'sureforms' ),
202 'status' => false,
203 ]
204 );
205 }
206
207 $form_data = Helper::sanitize_by_field_type( $request->get_params() );
208
209 if ( empty( $form_data ) || ! is_array( $form_data ) ) {
210 wp_send_json_error( __( 'Form data is not found.', 'sureforms' ) );
211 }
212
213 if ( ! $form_data['form-id'] ) {
214 wp_send_json_error( __( 'Form Id is missing.', 'sureforms' ) );
215 }
216 $current_form_id = $form_data['form-id'];
217 $security_type = Helper::get_meta_value( Helper::get_integer_value( $current_form_id ), '_srfm_captcha_security_type' );
218 $selected_captcha_type = get_post_meta( Helper::get_integer_value( $current_form_id ), '_srfm_form_recaptcha', true ) ? Helper::get_string_value( get_post_meta( Helper::get_integer_value( $current_form_id ), '_srfm_form_recaptcha', true ) ) : '';
219
220 if ( 'none' !== $security_type ) {
221 $global_setting_options = get_option( 'srfm_security_settings_options' );
222 } else {
223 $global_setting_options = [];
224 }
225
226 if ( 'g-recaptcha' === $security_type ) {
227 switch ( $selected_captcha_type ) {
228 case 'v2-checkbox':
229 $key = 'srfm_v2_checkbox_secret_key';
230 break;
231 case 'v2-invisible':
232 $key = 'srfm_v2_invisible_secret_key';
233 break;
234 case 'v3-reCAPTCHA':
235 $key = 'srfm_v3_secret_key';
236 break;
237 default:
238 $key = '';
239 break;
240 }
241
242 $google_captcha_secret_key = is_array( $global_setting_options ) && isset( $global_setting_options[ $key ] ) ? $global_setting_options[ $key ] : '';
243 }
244
245 if ( 'cf-turnstile' === $security_type ) {
246 // Turnstile validation.
247 $srfm_cf_turnstile_secret_key = is_array( $global_setting_options ) && isset( $global_setting_options['srfm_cf_turnstile_secret_key'] ) ? Helper::get_string_value( $global_setting_options['srfm_cf_turnstile_secret_key'] ) : '';
248 $cf_response = ! empty( $form_data['cf-turnstile-response'] ) ? $form_data['cf-turnstile-response'] : false;
249
250 // if gdpr is enabled then set remote ip to empty.
251 $compliance = get_post_meta( Helper::get_integer_value( $current_form_id ), '_srfm_compliance', true );
252 $gdpr = false;
253
254 if ( is_array( $compliance ) && is_array( $compliance[0] ) ) {
255 $gdpr = ! empty( $compliance[0]['gdpr'] ) ? $compliance[0]['gdpr'] : false;
256 }
257
258 // check if ip logging is disabled in global settings then set remote ip to empty.
259 $gb_general_settinionsgs_opt = get_option( 'srfm_general_settings_options' );
260 $srfm_ip_log = is_array( $gb_general_settinionsgs_opt ) && isset( $gb_general_settinionsgs_opt['srfm_ip_log'] ) ? $gb_general_settinionsgs_opt['srfm_ip_log'] : '';
261
262 $remote_ip = $gdpr || ( ! $srfm_ip_log ) ? '' : ( isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '' );
263
264 $turnstile_validation_result = self::validate_turnstile_token( $srfm_cf_turnstile_secret_key, $cf_response, $remote_ip );
265
266 // If the cloudflare validation fails, return an error.
267 if ( is_array( $turnstile_validation_result ) && isset( $turnstile_validation_result['success'] ) && false === $turnstile_validation_result['success'] ) {
268 $error_message = $turnstile_validation_result['error'] ?? __( 'Cloudflare Turnstile validation failed.', 'sureforms' );
269 return new \WP_Error( 'cf_turnstile_error', $error_message, [ 'status' => 403 ] );
270 }
271 }
272
273 if ( 'hcaptcha' === $security_type ) {
274 $srfm_hcaptcha_secret_key = is_array( $global_setting_options ) && isset( $global_setting_options['srfm_hcaptcha_secret_key'] ) ? Helper::get_string_value( $global_setting_options['srfm_hcaptcha_secret_key'] ) : '';
275 $hcaptcha_response = ! empty( $form_data['h-captcha-response'] ) ? $form_data['h-captcha-response'] : false;
276
277 // if gdpr is enabled then set remote ip to empty.
278 $compliance = get_post_meta( Helper::get_integer_value( $current_form_id ), '_srfm_compliance', true );
279 $gdpr = false;
280
281 if ( is_array( $compliance ) && is_array( $compliance[0] ) ) {
282 $gdpr = ! empty( $compliance[0]['gdpr'] ) ? $compliance[0]['gdpr'] : false;
283 }
284
285 // check if ip logging is disabled in global settings then set remote ip to empty.
286 $gb_general_settings_options = get_option( 'srfm_general_settings_options' );
287 $srfm_ip_log = is_array( $gb_general_settings_options ) && isset( $gb_general_settings_options['srfm_ip_log'] ) ? $gb_general_settings_options['srfm_ip_log'] : '';
288
289 $remote_ip = $gdpr || ( ! $srfm_ip_log ) ? '' : ( isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '' );
290 $hcaptcha_validation_result = self::validate_hcaptcha_token( $srfm_hcaptcha_secret_key, $hcaptcha_response, $remote_ip );
291
292 // If the hcaptcha validation fails, return an error.
293 if ( is_array( $hcaptcha_validation_result ) && isset( $hcaptcha_validation_result['success'] ) && false === $hcaptcha_validation_result['success'] ) {
294 $error_message = $hcaptcha_validation_result['error'] ?? __( 'hCaptcha validation failed.', 'sureforms' );
295 return new \WP_Error( 'hcaptcha_error', $error_message, [ 'status' => 403 ] );
296 }
297 }
298
299 if ( isset( $form_data['srfm-honeypot-field'] ) && empty( $form_data['srfm-honeypot-field'] ) ) {
300 if ( ! empty( $google_captcha_secret_key ) ) {
301 if ( isset( $form_data['sureforms_form_submit'] ) ) {
302 $secret_key = $google_captcha_secret_key;
303 $ipaddress = isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '';
304 $captcha_response = $form_data['g-recaptcha-response'];
305 $url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $secret_key . '&response=' . $captcha_response . '&ip=' . $ipaddress;
306
307 $response = wp_remote_get( $url );
308
309 if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
310 $json_string = wp_remote_retrieve_body( $response );
311 $data = (array) json_decode( $json_string, true );
312 } else {
313 $data = [];
314 }
315 $sureforms_captcha_data = $data;
316
317 } else {
318 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
319 }
320 if ( isset( $sureforms_captcha_data['success'] ) && true === $sureforms_captcha_data['success'] ) {
321 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
322 }
323 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
324
325 }
326 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
327
328 }
329 if ( ! isset( $form_data['srfm-honeypot-field'] ) ) {
330 if ( ! empty( $google_captcha_secret_key ) ) {
331 if ( isset( $form_data['sureforms_form_submit'] ) ) {
332 $secret_key = $google_captcha_secret_key;
333 $ipaddress = isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '';
334 $captcha_response = $form_data['g-recaptcha-response'];
335 $url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $secret_key . '&response=' . $captcha_response . '&ip=' . $ipaddress;
336
337 $response = wp_remote_get( $url );
338
339 if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
340 $json_string = wp_remote_retrieve_body( $response );
341 $data = (array) json_decode( $json_string, true );
342 } else {
343 $data = [];
344 }
345 $sureforms_captcha_data = $data;
346
347 } else {
348 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
349 }
350 if ( true === $sureforms_captcha_data['success'] ) {
351 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
352 }
353 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
354
355 }
356 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
357
358 }
359 return new \WP_Error( 'spam_detected', __( 'Spam Detected', 'sureforms' ), [ 'status' => 403 ] );
360 }
361
362 /**
363 * Change the upload directory
364 *
365 * @param array<mixed> $dirs upload directory.
366 * @return array<mixed>
367 * @since 0.0.1
368 */
369 public function change_upload_dir( $dirs ) {
370 $dirs['subdir'] = '/sureforms';
371 $dirs['path'] = $dirs['basedir'] . $dirs['subdir'];
372 $dirs['url'] = $dirs['baseurl'] . $dirs['subdir'];
373 return $dirs;
374 }
375
376 /**
377 * Send Email and Create Entry.
378 *
379 * @param array<string> $form_data Request object or array containing form data.
380 * @since 0.0.1
381 * @return array<mixed> Array containing the response data.
382 */
383 public function handle_form_entry( $form_data ) {
384 $is_error = false;
385 if ( defined( 'SRFM_PRO_VER' ) && isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] && ! empty( $_FILES ) ) {
386 add_filter( 'upload_dir', [ $this, 'change_upload_dir' ] );
387
388 // Get the file types.
389 $file_types = Helper::get_wp_file_types();
390
391 // Get the allowed file types.
392 $allowed_file_types = $file_types['formats'];
393
394 // Allowed file types should be array.
395 if ( ! is_array( $allowed_file_types ) ) {
396 $is_error = true;
397 wp_send_json_error(
398 [
399 'message' => __( 'File types are not allowed', 'sureforms' ),
400 ]
401 );
402 }
403
404 foreach ( $_FILES as $field => $file ) {
405 if ( is_array( $file['name'] ) ) {
406 foreach ( $file['name'] as $key => $filename ) {
407 $temp_path = $file['tmp_name'][ $key ];
408 $file_size = $file['size'][ $key ];
409 $file_type = $file['type'][ $key ];
410 $file_error = $file['error'][ $key ];
411
412 if ( ! $filename && ! $temp_path && ! $file_size && ! $file_type ) {
413 $form_data[ $field ][] = '';
414 continue;
415 }
416
417 // Check if the file type is allowed.
418 $get_file_type = explode( '/', $file_type );
419
420 // Check isset $get_file_type[1] it should be string.
421 if ( ! isset( $get_file_type[1] ) ) {
422 $is_error = true;
423 continue;
424 }
425
426 // $get_file_type[1] should be string.
427 if ( ! is_string( $get_file_type[1] ) ) {
428 $is_error = true;
429 continue;
430 }
431
432 // Check if the file type is allowed.
433 if ( ! in_array( $get_file_type[1], $allowed_file_types, true ) ) {
434 $is_error = true;
435 continue;
436 }
437
438 $uploaded_file = [
439 'name' => sanitize_file_name( $filename ),
440 'type' => $file_type,
441 'tmp_name' => $temp_path,
442 'error' => $file_error,
443 'size' => $file_size,
444 ];
445
446 $upload_overrides = [
447 'test_form' => false,
448 ];
449 $move_file = wp_handle_upload( $uploaded_file, $upload_overrides );
450 remove_filter( 'upload_dir', [ $this, 'change_upload_dir' ] );
451
452 if ( $move_file && ! isset( $move_file['error'] ) ) {
453 $form_data[ $field ][] = $move_file['url'];
454 } else {
455 $is_error = true;
456 continue;
457 }
458 }
459 } else {
460 $form_data[ $field ][] = '';
461 }
462 }
463 }
464
465 if ( $is_error ) {
466 wp_send_json_error(
467 [
468 'message' => __( 'File is not uploaded', 'sureforms' ),
469 ]
470 );
471 }
472
473 $id = sanitize_text_field( $form_data['form-id'] );
474
475 // Get the compliance settings.
476 $compliance = get_post_meta( Helper::get_integer_value( $id ), '_srfm_compliance', true );
477 $gdpr = '';
478 $do_not_store_entries = '';
479
480 if ( is_array( $compliance ) && is_array( $compliance[0] ) ) {
481 $gdpr = $compliance[0]['gdpr'] ?? '';
482 $do_not_store_entries = $compliance[0]['do_not_store_entries'] ?? '';
483 }
484
485 $submission_data = [];
486
487 $form_data_keys = array_keys( $form_data );
488 $form_data_count = count( $form_data );
489
490 for ( $i = 4; $i < $form_data_count; $i++ ) {
491 $key = strval( $form_data_keys[ $i ] );
492 $value = $form_data[ $key ];
493
494 $field_name = htmlspecialchars( str_replace( '_', ' ', $key ) );
495
496 // If the field is an array, encode the values. This is to add support for multi-upload field.
497 if ( is_array( $value ) ) {
498 $submission_data[ $field_name ] =
499 array_map(
500 static function ( $val ) {
501 return rawurlencode( $val );
502 },
503 $value
504 );
505 } else {
506 $submission_data[ $field_name ] = htmlspecialchars( $value );
507 }
508 }
509
510 $modified_message = $this->prepare_submission_data( $submission_data );
511
512 $form_before_submission_data = [
513 'form_id' => $id ? intval( $id ) : '',
514 'data' => $modified_message,
515 ];
516
517 /**
518 * Fires before submission process starts.
519 */
520 do_action( 'srfm_before_submission', $form_before_submission_data );
521
522 $name = sanitize_text_field( get_the_title( intval( $id ) ) );
523 $send_email = $this->send_email( $id, $submission_data, $form_data );
524 $emails = [];
525
526 if ( $send_email ) {
527 $emails = $send_email['emails'];
528 }
529
530 // Check if GDPR is enabled and do not store entries is enabled.
531 // If so, send email and do not store entries.
532 if ( $gdpr && $do_not_store_entries ) {
533
534 $form_submit_response = [
535 'success' => true,
536 'form_id' => $id ? intval( $id ) : '',
537 'to_emails' => $emails,
538 'form_name' => $name ? esc_attr( $name ) : '',
539 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
540 'data' => $modified_message,
541 ];
542
543 do_action( 'srfm_form_submit', $form_submit_response );
544
545 /**
546 * Hook for enabling background processes.
547 *
548 * @param array $form_data form data related to submission.
549 */
550 $form_data['form_id'] = $id ? intval( $id ) : '';
551 do_action( 'srfm_after_submission_process', $form_data );
552
553 return [
554 'success' => true,
555 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
556 'data' => [
557 'name' => $name,
558 'after_submit' => false,
559 ],
560 'redirect_url' => Generate_Form_Markup::get_redirect_url( $form_data, $submission_data ),
561 ];
562
563 }
564
565 $global_setting_options = get_option( 'srfm_general_settings_options' );
566
567 // If GDPR is enabled, do not store IP, browser, and device info.
568 // If not, store IP, browser, and device info.
569 $user_ip = '';
570 $browser_name = '';
571 $device_name = '';
572 if ( ! $gdpr ) {
573 $srfm_ip_log = is_array( $global_setting_options ) && isset( $global_setting_options['srfm_ip_log'] ) ? $global_setting_options['srfm_ip_log'] : '';
574
575 $user_ip = $srfm_ip_log && isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '';
576 $browser = new Browser();
577 $browser_name = sanitize_text_field( $browser->getBrowser() );
578 $device_name = sanitize_text_field( $browser->getPlatform() );
579 }
580
581 $form_markup = get_the_content( null, false, Helper::get_integer_value( $form_data['form-id'] ) );
582 $pattern = '/"label":"(.*?)"/';
583 preg_match_all( $pattern, $form_markup, $matches );
584 $submission_info = [
585 'user_ip' => $user_ip,
586 'browser_name' => $browser_name,
587 'device_name' => $device_name,
588 ];
589 $entries_data = [
590 'form_id' => $id,
591 'form_data' => $submission_data,
592 'submission_info' => $submission_info,
593 ];
594 if ( is_user_logged_in() ) {
595 // If user is logged in then save their user id.
596 $entries_data['user_id'] = get_current_user_id();
597 }
598 $entry_id = Entries::add( $entries_data );
599 if ( $entry_id ) {
600
601 $response = [
602 'success' => true,
603 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
604 'data' => [
605 'name' => $name,
606 'submission_id' => $entry_id,
607 'after_submit' => true,
608 ],
609 'redirect_url' => Generate_Form_Markup::get_redirect_url( $form_data, $submission_data ),
610 ];
611
612 $form_submit_response = apply_filters(
613 'srfm_form_submit_response',
614 [
615 'success' => true,
616 'form_id' => $id ? intval( $id ) : '',
617 'to_emails' => $emails,
618 'form_name' => $name ? esc_attr( $name ) : '',
619 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
620 'data' => $modified_message,
621 ]
622 );
623
624 do_action( 'srfm_form_submit', $form_submit_response );
625 } else {
626 $response = [
627 'success' => false,
628 'message' => __( 'Error submitting form', 'sureforms' ),
629 ];
630 }
631
632 return $response;
633 }
634
635 /**
636 * Prepare submission data.
637 *
638 * @param array<mixed> $submission_data Submission data.
639 * @since 0.0.7
640 * @return array<mixed> Modified submission data.
641 */
642 public function prepare_submission_data( $submission_data ) {
643 $modified_message = [];
644 foreach ( $submission_data as $key => $value ) {
645 $parts = explode( '-lbl-', $key );
646 $label = '';
647
648 if ( ! empty( $parts[1] ) ) {
649 $tokens = explode( '-', $parts[1] );
650 if ( count( $tokens ) > 1 ) {
651 $label = implode( '-', array_slice( $tokens, 1 ) );
652 }
653
654 $fields = explode( '-', $parts[0] );
655
656 // Since the upload field returns an array of file URLs, we need to implode them with a comma.
657 if ( 'upload' === $fields[1] && ! empty( $value ) && is_array( $value ) ) {
658 $modified_message[ $label ] = urldecode( implode( ', ', $value ) );
659 } else {
660 $modified_message[ $label ] = html_entity_decode( esc_attr( Helper::get_string_value( $value ) ) );
661 }
662 }
663 }
664
665 return $modified_message;
666 }
667
668 /**
669 * Send Email.
670 *
671 * @param string $id Form ID.
672 * @param array<mixed> $submission_data Submission data.
673 * @param array<string> $form_data Request object or array containing form data.
674 * @since 0.0.1
675 * @return array<mixed> Array containing the response data.
676 */
677 public static function send_email( $id, $submission_data, $form_data = [] ) {
678 $email_notification = get_post_meta( intval( $id ), '_srfm_email_notification' );
679 $smart_tags = new Smart_Tags();
680 $is_mail_sent = false;
681 $emails = [];
682
683 if ( is_iterable( $email_notification ) ) {
684 $entries_db_instance = Entries::get_instance();
685 $log_key = $entries_db_instance->add_log( __( 'Email Notification Initiated', 'sureforms' ) );
686
687 foreach ( $email_notification as $notification ) {
688 foreach ( $notification as $item ) {
689 if ( true === $item['status'] ) {
690 $from = Helper::get_string_value( get_option( 'admin_email' ) );
691 $to = $smart_tags->process_smart_tags( $item['email_to'], $submission_data );
692 $subject = $smart_tags->process_smart_tags( $item['subject'], $submission_data, $form_data );
693 $email_body = $smart_tags->process_smart_tags( $item['email_body'], $submission_data, $form_data );
694 $email_template = new Email_Template();
695 $message = $email_template->render( $submission_data, $email_body );
696 $headers = "From: {$from}\r\nX-Mailer: PHP/" . phpversion() . "\r\nContent-Type: text/html; charset=utf-8\r\n";
697 if ( isset( $item['email_reply_to'] ) && ! empty( $item['email_reply_to'] ) ) {
698 $headers .= 'Reply-To:' . $smart_tags->process_smart_tags( $item['email_reply_to'], $submission_data ) . "\r\n";
699 } else {
700 $headers .= "Reply-To: {$from}\r\n";
701 }
702 if ( isset( $item['email_cc'] ) && ! empty( $item['email_cc'] ) ) {
703 $headers .= 'Cc:' . $smart_tags->process_smart_tags( $item['email_cc'], $submission_data ) . "\r\n";
704 }
705 if ( isset( $item['email_bcc'] ) && ! empty( $item['email_bcc'] ) ) {
706 $headers .= 'Bcc:' . $smart_tags->process_smart_tags( $item['email_bcc'], $submission_data ) . "\r\n";
707 }
708
709 $sent = wp_mail( $to, $subject, $message, $headers );
710
711 if ( is_int( $log_key ) ) {
712 $entries_db_instance->update_log(
713 $log_key,
714 null,
715 [
716 /* translators: Here, %s is the comma separated emails list. */
717 $sent ? sprintf( __( 'Email notification sent to %s', 'sureforms' ), esc_html( $to ) ) : sprintf( __( 'Failed sending email notification to %s', 'sureforms' ), esc_html( $to ) ),
718 ]
719 );
720 }
721
722 $is_mail_sent = $sent;
723 $emails[] = $to;
724 }
725 }
726 }
727 }
728
729 return [
730 'success' => $is_mail_sent,
731 'emails' => $emails,
732 ];
733 }
734
735 /**
736 * Retrieve all entries data for a specific form ID to check for unique values.
737 *
738 * @since 0.0.1
739 * @return void
740 */
741 public function field_unique_validation() {
742 if ( isset( $_POST['nonce'] ) && ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'unique_validation_nonce' ) ) {
743 $error_message = __( 'Nonce verification failed.', 'sureforms' );
744 $error_data = [
745 'error' => $error_message,
746 ];
747 wp_send_json_error( $error_data );
748 }
749
750 global $wpdb;
751 $id = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
752 $meta_value = $id;
753
754 if ( ! $meta_value ) {
755 $error_message = __( 'Invalid form ID.', 'sureforms' );
756 $error_data = [
757 'error' => $error_message,
758 ];
759 wp_send_json_error( $error_data );
760 }
761
762 $_POST = array_map( 'wp_unslash', $_POST );
763
764 // Get the entry IDs for the particualr form to perform unique field validation.
765 $entry_ids = Entries::get_all_entry_ids_for_form( $id );
766
767 $all_form_entries = [];
768 $keys = array_keys( $_POST );
769 $length = count( $keys );
770
771 for ( $i = 3; $i < $length; $i++ ) {
772 $key = $keys[ $i ];
773 $value = isset( $_POST[ $key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $key ] ) ) : '';
774 $key = str_replace( '_', ' ', $keys[ $i ] );
775
776 foreach ( $entry_ids as $entry_id ) {
777 $entry_id = is_array( $entry_id ) ? Helper::get_integer_value( $entry_id['ID'] ) : 0;
778 $form_data = Entries::get_form_data( $entry_id );
779 if ( is_array( $form_data ) && isset( $form_data[ $key ] ) && $form_data[ $key ] === $value ) {
780 $obj = [ $key => 'not unique' ];
781 array_push( $all_form_entries, $obj );
782 break;
783 }
784 }
785 }
786
787 $results = [
788 'data' => $all_form_entries,
789 ];
790
791 wp_send_json( $results );
792 }
793
794 /**
795 * Function to save allowed block data.
796 *
797 * @since 0.0.1
798 * @return void
799 */
800 public function srfm_global_update_allowed_block() {
801 if ( ! current_user_can( 'manage_options' ) ) {
802 wp_send_json_error();
803 }
804
805 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
806 wp_send_json_error();
807 }
808
809 if ( ! empty( $_POST['defaultAllowedQuickSidebarBlocks'] ) ) {
810 $srfm_default_allowed_quick_sidebar_blocks = json_decode( sanitize_text_field( wp_unslash( $_POST['defaultAllowedQuickSidebarBlocks'] ) ), true );
811 Helper::update_admin_settings_option( 'srfm_quick_sidebar_allowed_blocks', $srfm_default_allowed_quick_sidebar_blocks );
812 wp_send_json_success();
813 }
814 wp_send_json_error();
815 }
816
817 /**
818 * Function to save enable/disable data.
819 *
820 * @since 0.0.1
821 * @return void
822 */
823 public function srfm_global_sidebar_enabled() {
824 if ( ! current_user_can( 'manage_options' ) ) {
825 wp_send_json_error();
826 }
827
828 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
829 wp_send_json_error();
830 }
831
832 if ( ! empty( $_POST['enableQuickActionSidebar'] ) ) {
833 $srfm_enable_quick_action_sidebar = ( 'enabled' === $_POST['enableQuickActionSidebar'] ? 'enabled' : 'disabled' );
834 Helper::update_admin_settings_option( 'srfm_enable_quick_action_sidebar', $srfm_enable_quick_action_sidebar );
835 wp_send_json_success();
836 }
837 wp_send_json_error();
838 }
839 }
840