PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 0.0.11
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v0.0.11
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 in SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz 0.0.11, at inc/form-submit.php

841 lines 27.2 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
550 $new_post = [
551 'post_status' => 'publish',
552 'post_type' => 'sureforms_entry',
553 ];
554
555 $post_id = wp_insert_post( $new_post );
556
557 $post_title = __( 'Entry #', 'sureforms' ) . $post_id;
558
559 $post_args = [
560 'ID' => $post_id,
561 'post_title' => $post_title,
562 ];
563
564 wp_update_post( $post_args );
565
566 update_post_meta( $post_id, 'srfm_entry_meta', $submission_data );
567 add_post_meta( $post_id, 'srfm_entry_meta_form_id', $id, true );
568 if ( $post_id ) {
569 $submission_info = [
570 'user_ip' => $user_ip,
571 'browser_name' => $browser_name,
572 'device_name' => $device_name,
573 ];
574
575 // Giving backward compatibility for Entries Post Type for now. It will be completed replaced with custom database table in next release.
576 $srfm_submission_info[] = $submission_info;
577 update_post_meta( $post_id, '_srfm_submission_info', $srfm_submission_info );
578 update_post_meta( $post_id, 'srfm_entry_meta', $submission_data );
579 update_post_meta( $post_id, '_srfm_entry_form_id', $id );
580
581 wp_set_object_terms( $post_id, $id, 'sureforms_tax' );
582
583 $response = [
584 'success' => true,
585 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
586 'data' => [
587 'name' => $name,
588 'submission_id' => $post_id,
589 'after_submit' => true,
590 ],
591 ];
592
593 $modified_message = $this->prepare_submission_data( $submission_data );
594
595 $form_submit_response = [
596 'success' => true,
597 'form_id' => $id ? intval( $id ) : '',
598 'to_emails' => $emails,
599 'form_name' => $name ? esc_attr( $name ) : '',
600 'message' => Generate_Form_Markup::get_confirmation_markup( $form_data, $submission_data ),
601 'data' => $modified_message,
602 ];
603
604 do_action( 'srfm_form_submit', $form_submit_response );
605
606 Entries::add(
607 [
608 'form_id' => $id,
609 'user_data' => $submission_data,
610 'submission_info' => $submission_info,
611 ]
612 );
613 } else {
614 $response = [
615 'success' => false,
616 'message' => __( 'Error submitting form', 'sureforms' ),
617 ];
618 }
619
620 return $response;
621 }
622
623 /**
624 * Prepare submission data.
625 *
626 * @param array<mixed> $submission_data Submission data.
627 * @since 0.0.7
628 * @return array<mixed> Modified submission data.
629 */
630 public function prepare_submission_data( $submission_data ) {
631 $modified_message = [];
632 foreach ( $submission_data as $key => $value ) {
633 $parts = explode( '-lbl-', $key );
634 $label = '';
635
636 if ( ! empty( $parts[1] ) ) {
637 $tokens = explode( '-', $parts[1] );
638 if ( count( $tokens ) > 1 ) {
639 $label = implode( '-', array_slice( $tokens, 1 ) );
640 }
641 $modified_message[ $label ] = html_entity_decode( esc_attr( Helper::get_string_value( $value ) ) );
642 }
643 }
644
645 return $modified_message;
646 }
647
648 /**
649 * Send Email.
650 *
651 * @param string $id Form ID.
652 * @param array<mixed> $submission_data Submission data.
653 * @since 0.0.1
654 * @return array<mixed> Array containing the response data.
655 */
656 public static function send_email( $id, $submission_data ) {
657 $email_notification = get_post_meta( intval( $id ), '_srfm_email_notification' );
658 $smart_tags = new Smart_Tags();
659 $is_mail_sent = false;
660 $emails = [];
661
662 if ( is_iterable( $email_notification ) ) {
663 $entries_db_instance = Entries::get_instance();
664 $log_key = $entries_db_instance->add_log( __( 'Email Notification Initiated', 'sureforms' ) );
665
666 foreach ( $email_notification as $notification ) {
667 foreach ( $notification as $item ) {
668 if ( true === $item['status'] ) {
669 $from = Helper::get_string_value( get_option( 'admin_email' ) );
670 $to = $smart_tags->process_smart_tags( $item['email_to'], $submission_data );
671 $subject = $smart_tags->process_smart_tags( $item['subject'], $submission_data );
672 $email_body = $smart_tags->process_smart_tags( $item['email_body'], $submission_data );
673 $email_template = new Email_Template();
674 $message = $email_template->render( $submission_data, $email_body );
675 $headers = "
676 From: $from\r\n" .
677 'X-Mailer: PHP/' . phpversion() . "\r\n" .
678 "Content-Type: text/html; charset=utf-8\r\n";
679 if ( isset( $item['email_reply_to'] ) && ! empty( $item['email_reply_to'] ) ) {
680 $headers .= 'Reply-To:' . $smart_tags->process_smart_tags( $item['email_reply_to'], $submission_data ) . "\r\n";
681 } else {
682 $headers .= "Reply-To: $from\r\n";
683 }
684 if ( isset( $item['email_cc'] ) && ! empty( $item['email_cc'] ) ) {
685 $headers .= 'Cc:' . $smart_tags->process_smart_tags( $item['email_cc'], $submission_data ) . "\r\n";
686 }
687 if ( isset( $item['email_bcc'] ) && ! empty( $item['email_bcc'] ) ) {
688 $headers .= 'Bcc:' . $smart_tags->process_smart_tags( $item['email_bcc'], $submission_data ) . "\r\n";
689 }
690
691 $sent = wp_mail( $to, $subject, $message, $headers );
692
693 if ( is_int( $log_key ) ) {
694 $entries_db_instance->update_log(
695 $log_key,
696 null,
697 [
698 /* translators: Here, %s is the comma separated emails list. */
699 $sent ? sprintf( __( 'Email notification sent to %s', 'sureforms' ), esc_html( $to ) ) : sprintf( __( 'Failed sending email notification to %s', 'sureforms' ) ),
700 ]
701 );
702 }
703
704 $is_mail_sent = $sent;
705 $emails[] = $to;
706 }
707 }
708 }
709 }
710
711 return [
712 'success' => $is_mail_sent,
713 'emails' => $emails,
714 ];
715
716 }
717
718 /**
719 * Retrieve all entries data for a specific form ID to check for unique values.
720 *
721 * @since 0.0.1
722 * @return void
723 */
724 public function field_unique_validation() {
725 if ( isset( $_POST['nonce'] ) && ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'unique_validation_nonce' ) ) {
726 $error_message = 'Nonce verification failed.';
727 $error_data = [
728 'error' => $error_message,
729 ];
730 wp_send_json_error( $error_data );
731 }
732
733 global $wpdb;
734 $id = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
735 $meta_value = $id;
736
737 if ( ! $meta_value ) {
738 $error_message = 'Invalid form ID.';
739 $error_data = [
740 'error' => $error_message,
741 ];
742 wp_send_json_error( $error_data );
743 }
744
745 $_POST = array_map( 'wp_unslash', $_POST );
746
747 $taxonomy = 'sureforms_tax';
748
749 $args = [
750 'post_type' => SRFM_ENTRIES_POST_TYPE,
751 'tax_query' // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query. -- We require tax_query for this function to work.
752 => [
753 [
754 'taxonomy' => $taxonomy,
755 'field' => 'slug',
756 'terms' => $id,
757 ],
758 ],
759 'fields' => 'ids',
760 ];
761 $query = new \WP_Query( $args );
762
763 $post_ids = $query->posts;
764
765 wp_reset_postdata();
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 ( $post_ids as $post_id ) {
777 $post_id = Helper::get_integer_value( $post_id );
778 $meta_values = get_post_meta( $post_id, 'srfm_entry_meta', true );
779 if ( is_array( $meta_values ) && isset( $meta_values[ $key ] ) && $meta_values[ $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 /**
796 * Function to save allowed block data.
797 *
798 * @since 0.0.1
799 * @return void
800 */
801 public function srfm_global_update_allowed_block() {
802 if ( ! current_user_can( 'manage_options' ) ) {
803 wp_send_json_error();
804 }
805
806 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
807 wp_send_json_error();
808 }
809
810 if ( ! empty( $_POST['defaultAllowedQuickSidebarBlocks'] ) ) {
811 $srfm_default_allowed_quick_sidebar_blocks = json_decode( sanitize_text_field( wp_unslash( $_POST['defaultAllowedQuickSidebarBlocks'] ) ), true );
812 Helper::update_admin_settings_option( 'srfm_quick_sidebar_allowed_blocks', $srfm_default_allowed_quick_sidebar_blocks );
813 wp_send_json_success();
814 }
815 wp_send_json_error();
816 }
817
818 /**
819 * Function to save enable/disable data.
820 *
821 * @since 0.0.1
822 * @return void
823 */
824 public function srfm_global_sidebar_enabled() {
825 if ( ! current_user_can( 'manage_options' ) ) {
826 wp_send_json_error();
827 }
828
829 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
830 wp_send_json_error();
831 }
832
833 if ( ! empty( $_POST['enableQuickActionSidebar'] ) ) {
834 $srfm_enable_quick_action_sidebar = ( 'enabled' === $_POST['enableQuickActionSidebar'] ? 'enabled' : 'disabled' );
835 Helper::update_admin_settings_option( 'srfm_enable_quick_action_sidebar', $srfm_enable_quick_action_sidebar );
836 wp_send_json_success();
837 }
838 wp_send_json_error();
839 }
840 }
841