PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 1.1.0
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v1.1.0
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
794 lines 26.4 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 ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] && ! empty( $_FILES ) ) {
214 add_filter( 'upload_dir', [ $this, 'change_upload_dir' ] );
215
216 foreach ( $_FILES as $field => $file ) {
217 if ( is_array( $file['name'] ) ) {
218 foreach ( $file['name'] as $key => $filename ) {
219 $temp_path = $file['tmp_name'][ $key ];
220 $file_size = $file['size'][ $key ];
221 $file_type = $file['type'][ $key ];
222 $file_error = $file['error'][ $key ];
223
224 if ( ! $filename && ! $temp_path && ! $file_size && ! $file_type ) {
225 $form_data[ $field ][] = '';
226 continue;
227 }
228
229 $uploaded_file = [
230 'name' => $filename,
231 'type' => $file_type,
232 'tmp_name' => $temp_path,
233 'error' => $file_error,
234 'size' => $file_size,
235 ];
236
237 $upload_overrides = [
238 'test_form' => false,
239 ];
240 $move_file = wp_handle_upload( $uploaded_file, $upload_overrides );
241 remove_filter( 'upload_dir', [ $this, 'change_upload_dir' ] );
242
243 if ( $move_file && ! isset( $move_file['error'] ) ) {
244 $form_data[ $field ][] = $move_file['url'];
245 } else {
246 wp_send_json_error( __( 'File is not uploaded', 'sureforms' ) );
247 }
248 }
249 } else {
250 $form_data[ $field ][] = '';
251 }
252 }
253 }
254
255 if ( ! $form_data['form-id'] ) {
256 wp_send_json_error( __( 'Form Id is missing.', 'sureforms' ) );
257 }
258 $current_form_id = $form_data['form-id'];
259 $security_type = Helper::get_meta_value( Helper::get_integer_value( $current_form_id ), '_srfm_captcha_security_type' );
260 $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 ) ) : '';
261
262 if ( 'none' !== $security_type ) {
263 $global_setting_options = get_option( 'srfm_security_settings_options' );
264 } else {
265 $global_setting_options = [];
266 }
267
268 if ( 'g-recaptcha' === $security_type ) {
269 switch ( $selected_captcha_type ) {
270 case 'v2-checkbox':
271 $key = 'srfm_v2_checkbox_secret_key';
272 break;
273 case 'v2-invisible':
274 $key = 'srfm_v2_invisible_secret_key';
275 break;
276 case 'v3-reCAPTCHA':
277 $key = 'srfm_v3_secret_key';
278 break;
279 default:
280 $key = '';
281 break;
282 }
283
284 $google_captcha_secret_key = is_array( $global_setting_options ) && isset( $global_setting_options[ $key ] ) ? $global_setting_options[ $key ] : '';
285 }
286
287 if ( 'cf-turnstile' === $security_type ) {
288 // Turnstile validation.
289 $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'] ) : '';
290 $cf_response = ! empty( $form_data['cf-turnstile-response'] ) ? $form_data['cf-turnstile-response'] : false;
291
292 // if gdpr is enabled then set remote ip to empty.
293 $compliance = get_post_meta( Helper::get_integer_value( $current_form_id ), '_srfm_compliance', true );
294 $gdpr = false;
295
296 if ( is_array( $compliance ) && is_array( $compliance[0] ) ) {
297 $gdpr = ! empty( $compliance[0]['gdpr'] ) ? $compliance[0]['gdpr'] : false;
298 }
299
300 // check if ip logging is disabled in global settings then set remote ip to empty.
301 $gb_general_settinionsgs_opt = get_option( 'srfm_general_settings_options' );
302 $srfm_ip_log = is_array( $gb_general_settinionsgs_opt ) && isset( $gb_general_settinionsgs_opt['srfm_ip_log'] ) ? $gb_general_settinionsgs_opt['srfm_ip_log'] : '';
303
304 $remote_ip = $gdpr || ( ! $srfm_ip_log ) ? '' : ( isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '' );
305
306 $turnstile_validation_result = self::validate_turnstile_token( $srfm_cf_turnstile_secret_key, $cf_response, $remote_ip );
307
308 // If the cloudflare validation fails, return an error.
309 if ( is_array( $turnstile_validation_result ) && isset( $turnstile_validation_result['success'] ) && false === $turnstile_validation_result['success'] ) {
310 $error_message = $turnstile_validation_result['error'] ?? __( 'Cloudflare Turnstile validation failed.', 'sureforms' );
311 return new \WP_Error( 'cf_turnstile_error', $error_message, [ 'status' => 403 ] );
312 }
313 }
314
315 if ( 'hcaptcha' === $security_type ) {
316 $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'] ) : '';
317 $hcaptcha_response = ! empty( $form_data['h-captcha-response'] ) ? $form_data['h-captcha-response'] : false;
318
319 // if gdpr is enabled then set remote ip to empty.
320 $compliance = get_post_meta( Helper::get_integer_value( $current_form_id ), '_srfm_compliance', true );
321 $gdpr = false;
322
323 if ( is_array( $compliance ) && is_array( $compliance[0] ) ) {
324 $gdpr = ! empty( $compliance[0]['gdpr'] ) ? $compliance[0]['gdpr'] : false;
325 }
326
327 // check if ip logging is disabled in global settings then set remote ip to empty.
328 $gb_general_settings_options = get_option( 'srfm_general_settings_options' );
329 $srfm_ip_log = is_array( $gb_general_settings_options ) && isset( $gb_general_settings_options['srfm_ip_log'] ) ? $gb_general_settings_options['srfm_ip_log'] : '';
330
331 $remote_ip = $gdpr || ( ! $srfm_ip_log ) ? '' : ( isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '' );
332 $hcaptcha_validation_result = self::validate_hcaptcha_token( $srfm_hcaptcha_secret_key, $hcaptcha_response, $remote_ip );
333
334 // If the hcaptcha validation fails, return an error.
335 if ( is_array( $hcaptcha_validation_result ) && isset( $hcaptcha_validation_result['success'] ) && false === $hcaptcha_validation_result['success'] ) {
336 $error_message = $hcaptcha_validation_result['error'] ?? __( 'hCaptcha validation failed.', 'sureforms' );
337 return new \WP_Error( 'hcaptcha_error', $error_message, [ 'status' => 403 ] );
338 }
339 }
340
341 if ( isset( $form_data['srfm-honeypot-field'] ) && empty( $form_data['srfm-honeypot-field'] ) ) {
342 if ( ! empty( $google_captcha_secret_key ) ) {
343 if ( isset( $form_data['sureforms_form_submit'] ) ) {
344 $secret_key = $google_captcha_secret_key;
345 $ipaddress = isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '';
346 $captcha_response = $form_data['g-recaptcha-response'];
347 $url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $secret_key . '&response=' . $captcha_response . '&ip=' . $ipaddress;
348
349 $response = wp_remote_get( $url );
350
351 if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
352 $json_string = wp_remote_retrieve_body( $response );
353 $data = (array) json_decode( $json_string, true );
354 } else {
355 $data = [];
356 }
357 $sureforms_captcha_data = $data;
358
359 } else {
360 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
361 }
362 if ( isset( $sureforms_captcha_data['success'] ) && true === $sureforms_captcha_data['success'] ) {
363 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
364 }
365 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
366
367 }
368 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
369
370 }
371 if ( ! isset( $form_data['srfm-honeypot-field'] ) ) {
372 if ( ! empty( $google_captcha_secret_key ) ) {
373 if ( isset( $form_data['sureforms_form_submit'] ) ) {
374 $secret_key = $google_captcha_secret_key;
375 $ipaddress = isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '';
376 $captcha_response = $form_data['g-recaptcha-response'];
377 $url = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $secret_key . '&response=' . $captcha_response . '&ip=' . $ipaddress;
378
379 $response = wp_remote_get( $url );
380
381 if ( ! is_wp_error( $response ) && wp_remote_retrieve_response_code( $response ) === 200 ) {
382 $json_string = wp_remote_retrieve_body( $response );
383 $data = (array) json_decode( $json_string, true );
384 } else {
385 $data = [];
386 }
387 $sureforms_captcha_data = $data;
388
389 } else {
390 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
391 }
392 if ( true === $sureforms_captcha_data['success'] ) {
393 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
394 }
395 return new \WP_Error( 'recaptcha_error', __( 'reCAPTCHA error.', 'sureforms' ), [ 'status' => 403 ] );
396
397 }
398 return rest_ensure_response( $this->handle_form_entry( $form_data ) );
399
400 }
401 return new \WP_Error( 'spam_detected', __( 'Spam Detected', 'sureforms' ), [ 'status' => 403 ] );
402 }
403
404 /**
405 * Change the upload directory
406 *
407 * @param array<mixed> $dirs upload directory.
408 * @return array<mixed>
409 * @since 0.0.1
410 */
411 public function change_upload_dir( $dirs ) {
412 $dirs['subdir'] = '/sureforms';
413 $dirs['path'] = $dirs['basedir'] . $dirs['subdir'];
414 $dirs['url'] = $dirs['baseurl'] . $dirs['subdir'];
415 return $dirs;
416 }
417
418 /**
419 * Send Email and Create Entry.
420 *
421 * @param array<string> $form_data Request object or array containing form data.
422 * @since 0.0.1
423 * @return array<mixed> Array containing the response data.
424 */
425 public function handle_form_entry( $form_data ) {
426
427 $id = sanitize_text_field( $form_data['form-id'] );
428
429 // Get the compliance settings.
430 $compliance = get_post_meta( Helper::get_integer_value( $id ), '_srfm_compliance', true );
431 $gdpr = '';
432 $do_not_store_entries = '';
433
434 if ( is_array( $compliance ) && is_array( $compliance[0] ) ) {
435 $gdpr = $compliance[0]['gdpr'] ?? '';
436 $do_not_store_entries = $compliance[0]['do_not_store_entries'] ?? '';
437 }
438
439 $submission_data = [];
440
441 $form_data_keys = array_keys( $form_data );
442 $form_data_count = count( $form_data );
443
444 for ( $i = 4; $i < $form_data_count; $i++ ) {
445 $key = strval( $form_data_keys[ $i ] );
446 $value = $form_data[ $key ];
447
448 $field_name = htmlspecialchars( str_replace( '_', ' ', $key ) );
449
450 // If the field is an array, encode the values. This is to add support for multi-upload field.
451 if ( is_array( $value ) ) {
452 $submission_data[ $field_name ] =
453 array_map(
454 static function ( $val ) {
455 return rawurlencode( $val );
456 },
457 $value
458 );
459 } else {
460 $submission_data[ $field_name ] = htmlspecialchars( $value );
461 }
462 }
463
464 $modified_message = $this->prepare_submission_data( $submission_data );
465
466 $form_before_submission_data = [
467 'form_id' => $id ? intval( $id ) : '',
468 'data' => $modified_message,
469 ];
470
471 /**
472 * Fires before submission process starts.
473 */
474 do_action( 'srfm_before_submission', $form_before_submission_data );
475
476 $name = sanitize_text_field( get_the_title( intval( $id ) ) );
477 $send_email = $this->send_email( $id, $submission_data, $form_data );
478 $emails = [];
479
480 if ( $send_email ) {
481 $emails = $send_email['emails'];
482 }
483
484 // Check if GDPR is enabled and do not store entries is enabled.
485 // If so, send email and do not store entries.
486 if ( $gdpr && $do_not_store_entries ) {
487
488 $form_submit_response = [
489 'success' => true,
490 'form_id' => $id ? intval( $id ) : '',
491 'to_emails' => $emails,
492 'form_name' => $name ? esc_attr( $name ) : '',
493 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
494 'data' => $modified_message,
495 ];
496
497 do_action( 'srfm_form_submit', $form_submit_response );
498
499 /**
500 * Hook for enabling background processes.
501 *
502 * @param array $form_data form data related to submission.
503 */
504 $form_data['form_id'] = $id ? intval( $id ) : '';
505 do_action( 'srfm_after_submission_process', $form_data );
506
507 return [
508 'success' => true,
509 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
510 'data' => [
511 'name' => $name,
512 'after_submit' => false,
513 ],
514 'redirect_url' => Generate_Form_Markup::get_redirect_url( $form_data, $submission_data ),
515 ];
516
517 }
518
519 $global_setting_options = get_option( 'srfm_general_settings_options' );
520
521 // If GDPR is enabled, do not store IP, browser, and device info.
522 // If not, store IP, browser, and device info.
523 $user_ip = '';
524 $browser_name = '';
525 $device_name = '';
526 if ( ! $gdpr ) {
527 $srfm_ip_log = is_array( $global_setting_options ) && isset( $global_setting_options['srfm_ip_log'] ) ? $global_setting_options['srfm_ip_log'] : '';
528
529 $user_ip = $srfm_ip_log && isset( $_SERVER['REMOTE_ADDR'] ) ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ), FILTER_VALIDATE_IP ) : '';
530 $browser = new Browser();
531 $browser_name = sanitize_text_field( $browser->getBrowser() );
532 $device_name = sanitize_text_field( $browser->getPlatform() );
533 }
534
535 $form_markup = get_the_content( null, false, Helper::get_integer_value( $form_data['form-id'] ) );
536 $pattern = '/"label":"(.*?)"/';
537 preg_match_all( $pattern, $form_markup, $matches );
538 $submission_info = [
539 'user_ip' => $user_ip,
540 'browser_name' => $browser_name,
541 'device_name' => $device_name,
542 ];
543 $entries_data = [
544 'form_id' => $id,
545 'form_data' => $submission_data,
546 'submission_info' => $submission_info,
547 ];
548 if ( is_user_logged_in() ) {
549 // If user is logged in then save their user id.
550 $entries_data['user_id'] = get_current_user_id();
551 }
552 $entry_id = Entries::add( $entries_data );
553 if ( $entry_id ) {
554
555 $response = [
556 'success' => true,
557 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
558 'data' => [
559 'name' => $name,
560 'submission_id' => $entry_id,
561 'after_submit' => true,
562 ],
563 'redirect_url' => Generate_Form_Markup::get_redirect_url( $form_data, $submission_data ),
564 ];
565
566 $form_submit_response = apply_filters(
567 'srfm_form_submit_response',
568 [
569 'success' => true,
570 'form_id' => $id ? intval( $id ) : '',
571 'to_emails' => $emails,
572 'form_name' => $name ? esc_attr( $name ) : '',
573 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
574 'data' => $modified_message,
575 ]
576 );
577
578 do_action( 'srfm_form_submit', $form_submit_response );
579 } else {
580 $response = [
581 'success' => false,
582 'message' => __( 'Error submitting form', 'sureforms' ),
583 ];
584 }
585
586 return $response;
587 }
588
589 /**
590 * Prepare submission data.
591 *
592 * @param array<mixed> $submission_data Submission data.
593 * @since 0.0.7
594 * @return array<mixed> Modified submission data.
595 */
596 public function prepare_submission_data( $submission_data ) {
597 $modified_message = [];
598 foreach ( $submission_data as $key => $value ) {
599 $parts = explode( '-lbl-', $key );
600 $label = '';
601
602 if ( ! empty( $parts[1] ) ) {
603 $tokens = explode( '-', $parts[1] );
604 if ( count( $tokens ) > 1 ) {
605 $label = implode( '-', array_slice( $tokens, 1 ) );
606 }
607
608 $fields = explode( '-', $parts[0] );
609
610 // Since the upload field returns an array of file URLs, we need to implode them with a comma.
611 if ( 'upload' === $fields[1] && ! empty( $value ) && is_array( $value ) ) {
612 $modified_message[ $label ] = urldecode( implode( ', ', $value ) );
613 } else {
614 $modified_message[ $label ] = html_entity_decode( esc_attr( Helper::get_string_value( $value ) ) );
615 }
616 }
617 }
618
619 return $modified_message;
620 }
621
622 /**
623 * Send Email.
624 *
625 * @param string $id Form ID.
626 * @param array<mixed> $submission_data Submission data.
627 * @param array<string> $form_data Request object or array containing form data.
628 * @since 0.0.1
629 * @return array<mixed> Array containing the response data.
630 */
631 public static function send_email( $id, $submission_data, $form_data = [] ) {
632 $email_notification = get_post_meta( intval( $id ), '_srfm_email_notification' );
633 $smart_tags = new Smart_Tags();
634 $is_mail_sent = false;
635 $emails = [];
636
637 if ( is_iterable( $email_notification ) ) {
638 $entries_db_instance = Entries::get_instance();
639 $log_key = $entries_db_instance->add_log( __( 'Email Notification Initiated', 'sureforms' ) );
640
641 foreach ( $email_notification as $notification ) {
642 foreach ( $notification as $item ) {
643 if ( true === $item['status'] ) {
644 $from = Helper::get_string_value( get_option( 'admin_email' ) );
645 $to = $smart_tags->process_smart_tags( $item['email_to'], $submission_data );
646 $subject = $smart_tags->process_smart_tags( $item['subject'], $submission_data, $form_data );
647 $email_body = $smart_tags->process_smart_tags( $item['email_body'], $submission_data, $form_data );
648 $email_template = new Email_Template();
649 $message = $email_template->render( $submission_data, $email_body );
650 $headers = "From: {$from}\r\nX-Mailer: PHP/" . phpversion() . "\r\nContent-Type: text/html; charset=utf-8\r\n";
651 if ( isset( $item['email_reply_to'] ) && ! empty( $item['email_reply_to'] ) ) {
652 $headers .= 'Reply-To:' . $smart_tags->process_smart_tags( $item['email_reply_to'], $submission_data ) . "\r\n";
653 } else {
654 $headers .= "Reply-To: {$from}\r\n";
655 }
656 if ( isset( $item['email_cc'] ) && ! empty( $item['email_cc'] ) ) {
657 $headers .= 'Cc:' . $smart_tags->process_smart_tags( $item['email_cc'], $submission_data ) . "\r\n";
658 }
659 if ( isset( $item['email_bcc'] ) && ! empty( $item['email_bcc'] ) ) {
660 $headers .= 'Bcc:' . $smart_tags->process_smart_tags( $item['email_bcc'], $submission_data ) . "\r\n";
661 }
662
663 $sent = wp_mail( $to, $subject, $message, $headers );
664
665 if ( is_int( $log_key ) ) {
666 $entries_db_instance->update_log(
667 $log_key,
668 null,
669 [
670 /* translators: Here, %s is the comma separated emails list. */
671 $sent ? sprintf( __( 'Email notification sent to %s', 'sureforms' ), esc_html( $to ) ) : sprintf( __( 'Failed sending email notification to %s', 'sureforms' ), esc_html( $to ) ),
672 ]
673 );
674 }
675
676 $is_mail_sent = $sent;
677 $emails[] = $to;
678 }
679 }
680 }
681 }
682
683 return [
684 'success' => $is_mail_sent,
685 'emails' => $emails,
686 ];
687 }
688
689 /**
690 * Retrieve all entries data for a specific form ID to check for unique values.
691 *
692 * @since 0.0.1
693 * @return void
694 */
695 public function field_unique_validation() {
696 if ( isset( $_POST['nonce'] ) && ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'unique_validation_nonce' ) ) {
697 $error_message = __( 'Nonce verification failed.', 'sureforms' );
698 $error_data = [
699 'error' => $error_message,
700 ];
701 wp_send_json_error( $error_data );
702 }
703
704 global $wpdb;
705 $id = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
706 $meta_value = $id;
707
708 if ( ! $meta_value ) {
709 $error_message = __( 'Invalid form ID.', 'sureforms' );
710 $error_data = [
711 'error' => $error_message,
712 ];
713 wp_send_json_error( $error_data );
714 }
715
716 $_POST = array_map( 'wp_unslash', $_POST );
717
718 // Get the entry IDs for the particualr form to perform unique field validation.
719 $entry_ids = Entries::get_all_entry_ids_for_form( $id );
720
721 $all_form_entries = [];
722 $keys = array_keys( $_POST );
723 $length = count( $keys );
724
725 for ( $i = 3; $i < $length; $i++ ) {
726 $key = $keys[ $i ];
727 $value = isset( $_POST[ $key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $key ] ) ) : '';
728 $key = str_replace( '_', ' ', $keys[ $i ] );
729
730 foreach ( $entry_ids as $entry_id ) {
731 $entry_id = is_array( $entry_id ) ? Helper::get_integer_value( $entry_id['ID'] ) : 0;
732 $form_data = Entries::get_form_data( $entry_id );
733 if ( is_array( $form_data ) && isset( $form_data[ $key ] ) && $form_data[ $key ] === $value ) {
734 $obj = [ $key => 'not unique' ];
735 array_push( $all_form_entries, $obj );
736 break;
737 }
738 }
739 }
740
741 $results = [
742 'data' => $all_form_entries,
743 ];
744
745 wp_send_json( $results );
746 }
747
748 /**
749 * Function to save allowed block data.
750 *
751 * @since 0.0.1
752 * @return void
753 */
754 public function srfm_global_update_allowed_block() {
755 if ( ! current_user_can( 'manage_options' ) ) {
756 wp_send_json_error();
757 }
758
759 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
760 wp_send_json_error();
761 }
762
763 if ( ! empty( $_POST['defaultAllowedQuickSidebarBlocks'] ) ) {
764 $srfm_default_allowed_quick_sidebar_blocks = json_decode( sanitize_text_field( wp_unslash( $_POST['defaultAllowedQuickSidebarBlocks'] ) ), true );
765 Helper::update_admin_settings_option( 'srfm_quick_sidebar_allowed_blocks', $srfm_default_allowed_quick_sidebar_blocks );
766 wp_send_json_success();
767 }
768 wp_send_json_error();
769 }
770
771 /**
772 * Function to save enable/disable data.
773 *
774 * @since 0.0.1
775 * @return void
776 */
777 public function srfm_global_sidebar_enabled() {
778 if ( ! current_user_can( 'manage_options' ) ) {
779 wp_send_json_error();
780 }
781
782 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
783 wp_send_json_error();
784 }
785
786 if ( ! empty( $_POST['enableQuickActionSidebar'] ) ) {
787 $srfm_enable_quick_action_sidebar = ( 'enabled' === $_POST['enableQuickActionSidebar'] ? 'enabled' : 'disabled' );
788 Helper::update_admin_settings_option( 'srfm_enable_quick_action_sidebar', $srfm_enable_quick_action_sidebar );
789 wp_send_json_success();
790 }
791 wp_send_json_error();
792 }
793 }
794