PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 0.0.13
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v0.0.13
2.12.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 All 97 releases
sureforms / inc / form-submit.php

form-submit.php in SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz 0.0.13, at inc/form-submit.php

854 lines 27.7 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_data = [
607 'form_id' => $id,
608 'form_data' => $submission_data,
609 'submission_info' => $submission_info,
610 ];
611
612 if ( is_user_logged_in() ) {
613 // If user is logged in then save their user id.
614 $entries_data['user_id'] = get_current_user_id();
615 }
616
617 Entries::add( $entries_data );
618 } else {
619 $response = [
620 'success' => false,
621 'message' => __( 'Error submitting form', 'sureforms' ),
622 ];
623 }
624
625 return $response;
626 }
627
628 /**
629 * Prepare submission data.
630 *
631 * @param array<mixed> $submission_data Submission data.
632 * @since 0.0.7
633 * @return array<mixed> Modified submission data.
634 */
635 public function prepare_submission_data( $submission_data ) {
636 $modified_message = [];
637 foreach ( $submission_data as $key => $value ) {
638 $parts = explode( '-lbl-', $key );
639 $label = '';
640
641 if ( ! empty( $parts[1] ) ) {
642 $tokens = explode( '-', $parts[1] );
643 if ( count( $tokens ) > 1 ) {
644 $label = implode( '-', array_slice( $tokens, 1 ) );
645 }
646
647 $fields = explode( '-', $parts[0] );
648
649 // Since the upload field returns an array of file URLs, we need to implode them with a comma.
650 if ( 'upload' === $fields[1] && ! empty( $value ) && is_array( $value ) ) {
651 $modified_message[ $label ] = urldecode( implode( ', ', $value ) );
652 } else {
653 $modified_message[ $label ] = html_entity_decode( esc_attr( Helper::get_string_value( $value ) ) );
654 }
655 }
656 }
657
658 return $modified_message;
659 }
660
661 /**
662 * Send Email.
663 *
664 * @param string $id Form ID.
665 * @param array<mixed> $submission_data Submission data.
666 * @since 0.0.1
667 * @return array<mixed> Array containing the response data.
668 */
669 public static function send_email( $id, $submission_data ) {
670 $email_notification = get_post_meta( intval( $id ), '_srfm_email_notification' );
671 $smart_tags = new Smart_Tags();
672 $is_mail_sent = false;
673 $emails = [];
674
675 if ( is_iterable( $email_notification ) ) {
676 $entries_db_instance = Entries::get_instance();
677 $log_key = $entries_db_instance->add_log( __( 'Email Notification Initiated', 'sureforms' ) );
678
679 foreach ( $email_notification as $notification ) {
680 foreach ( $notification as $item ) {
681 if ( true === $item['status'] ) {
682 $from = Helper::get_string_value( get_option( 'admin_email' ) );
683 $to = $smart_tags->process_smart_tags( $item['email_to'], $submission_data );
684 $subject = $smart_tags->process_smart_tags( $item['subject'], $submission_data );
685 $email_body = $smart_tags->process_smart_tags( $item['email_body'], $submission_data );
686 $email_template = new Email_Template();
687 $message = $email_template->render( $submission_data, $email_body );
688 $headers = "
689 From: $from\r\n" .
690 'X-Mailer: PHP/' . phpversion() . "\r\n" .
691 "Content-Type: text/html; charset=utf-8\r\n";
692 if ( isset( $item['email_reply_to'] ) && ! empty( $item['email_reply_to'] ) ) {
693 $headers .= 'Reply-To:' . $smart_tags->process_smart_tags( $item['email_reply_to'], $submission_data ) . "\r\n";
694 } else {
695 $headers .= "Reply-To: $from\r\n";
696 }
697 if ( isset( $item['email_cc'] ) && ! empty( $item['email_cc'] ) ) {
698 $headers .= 'Cc:' . $smart_tags->process_smart_tags( $item['email_cc'], $submission_data ) . "\r\n";
699 }
700 if ( isset( $item['email_bcc'] ) && ! empty( $item['email_bcc'] ) ) {
701 $headers .= 'Bcc:' . $smart_tags->process_smart_tags( $item['email_bcc'], $submission_data ) . "\r\n";
702 }
703
704 $sent = wp_mail( $to, $subject, $message, $headers );
705
706 if ( is_int( $log_key ) ) {
707 $entries_db_instance->update_log(
708 $log_key,
709 null,
710 [
711 /* translators: Here, %s is the comma separated emails list. */
712 $sent ? sprintf( __( 'Email notification sent to %s', 'sureforms' ), esc_html( $to ) ) : sprintf( __( 'Failed sending email notification to %s', 'sureforms' ) ),
713 ]
714 );
715 }
716
717 $is_mail_sent = $sent;
718 $emails[] = $to;
719 }
720 }
721 }
722 }
723
724 return [
725 'success' => $is_mail_sent,
726 'emails' => $emails,
727 ];
728
729 }
730
731 /**
732 * Retrieve all entries data for a specific form ID to check for unique values.
733 *
734 * @since 0.0.1
735 * @return void
736 */
737 public function field_unique_validation() {
738 if ( isset( $_POST['nonce'] ) && ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'unique_validation_nonce' ) ) {
739 $error_message = 'Nonce verification failed.';
740 $error_data = [
741 'error' => $error_message,
742 ];
743 wp_send_json_error( $error_data );
744 }
745
746 global $wpdb;
747 $id = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
748 $meta_value = $id;
749
750 if ( ! $meta_value ) {
751 $error_message = 'Invalid form ID.';
752 $error_data = [
753 'error' => $error_message,
754 ];
755 wp_send_json_error( $error_data );
756 }
757
758 $_POST = array_map( 'wp_unslash', $_POST );
759
760 $taxonomy = 'sureforms_tax';
761
762 $args = [
763 'post_type' => SRFM_ENTRIES_POST_TYPE,
764 'tax_query' // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query. -- We require tax_query for this function to work.
765 => [
766 [
767 'taxonomy' => $taxonomy,
768 'field' => 'slug',
769 'terms' => $id,
770 ],
771 ],
772 'fields' => 'ids',
773 ];
774 $query = new \WP_Query( $args );
775
776 $post_ids = $query->posts;
777
778 wp_reset_postdata();
779
780 $all_form_entries = [];
781 $keys = array_keys( $_POST );
782 $length = count( $keys );
783
784 for ( $i = 3; $i < $length; $i++ ) {
785 $key = $keys[ $i ];
786 $value = isset( $_POST[ $key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $key ] ) ) : '';
787 $key = str_replace( '_', ' ', $keys[ $i ] );
788
789 foreach ( $post_ids as $post_id ) {
790 $post_id = Helper::get_integer_value( $post_id );
791 $meta_values = get_post_meta( $post_id, 'srfm_entry_meta', true );
792 if ( is_array( $meta_values ) && isset( $meta_values[ $key ] ) && $meta_values[ $key ] === $value ) {
793 $obj = [ $key => 'not unique' ];
794 array_push( $all_form_entries, $obj );
795 break;
796 }
797 }
798 }
799
800 $results = [
801 'data' => $all_form_entries,
802 ];
803
804 wp_send_json( $results );
805 }
806
807
808 /**
809 * Function to save allowed block data.
810 *
811 * @since 0.0.1
812 * @return void
813 */
814 public function srfm_global_update_allowed_block() {
815 if ( ! current_user_can( 'manage_options' ) ) {
816 wp_send_json_error();
817 }
818
819 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
820 wp_send_json_error();
821 }
822
823 if ( ! empty( $_POST['defaultAllowedQuickSidebarBlocks'] ) ) {
824 $srfm_default_allowed_quick_sidebar_blocks = json_decode( sanitize_text_field( wp_unslash( $_POST['defaultAllowedQuickSidebarBlocks'] ) ), true );
825 Helper::update_admin_settings_option( 'srfm_quick_sidebar_allowed_blocks', $srfm_default_allowed_quick_sidebar_blocks );
826 wp_send_json_success();
827 }
828 wp_send_json_error();
829 }
830
831 /**
832 * Function to save enable/disable data.
833 *
834 * @since 0.0.1
835 * @return void
836 */
837 public function srfm_global_sidebar_enabled() {
838 if ( ! current_user_can( 'manage_options' ) ) {
839 wp_send_json_error();
840 }
841
842 if ( ! check_ajax_referer( 'srfm_ajax_nonce', 'security', false ) ) {
843 wp_send_json_error();
844 }
845
846 if ( ! empty( $_POST['enableQuickActionSidebar'] ) ) {
847 $srfm_enable_quick_action_sidebar = ( 'enabled' === $_POST['enableQuickActionSidebar'] ? 'enabled' : 'disabled' );
848 Helper::update_admin_settings_option( 'srfm_enable_quick_action_sidebar', $srfm_enable_quick_action_sidebar );
849 wp_send_json_success();
850 }
851 wp_send_json_error();
852 }
853 }
854