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