PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.16.3
GiveWP – Donation Plugin and Fundraising Platform v3.16.3
4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / process-donation.php
give / includes Last commit date
admin 1 year ago api 3 years ago database 2 years ago deprecated 3 years ago donors 1 year ago emails 4 years ago forms 1 year ago frontend 6 years ago gateways 2 years ago libraries 2 years ago payments 2 years ago actions.php 5 years ago ajax-functions.php 3 years ago class-give-async-process.php 1 year ago class-give-background-updater.php 2 years ago class-give-cache-setting.php 2 years ago class-give-cache.php 3 years ago class-give-cli-commands.php 3 years ago class-give-comment.php 6 years ago class-give-cron.php 6 years ago class-give-donate-form.php 2 years ago class-give-donor.php 2 years ago class-give-email-access.php 5 years ago class-give-license-handler.php 4 years ago class-give-logging.php 5 years ago class-give-readme-parser.php 4 years ago class-give-roles.php 6 years ago class-give-scripts.php 2 years ago class-give-session.php 5 years ago class-give-stats.php 6 years ago class-give-template-loader.php 6 years ago class-give-tooltips.php 6 years ago class-give-translation.php 4 years ago class-notices.php 2 years ago country-functions.php 5 years ago currencies-list.php 3 years ago currency-functions.php 4 years ago error-tracking.php 6 years ago filters.php 3 years ago formatting.php 2 years ago install.php 2 years ago login-register.php 2 years ago misc-functions.php 1 year ago plugin-compatibility.php 6 years ago post-types.php 5 years ago price-functions.php 6 years ago process-donation.php 1 year ago setting-functions.php 7 years ago shortcodes.php 1 year ago template-functions.php 4 years ago user-functions.php 3 years ago
process-donation.php
1672 lines
1 <?php
2 /**
3 * Process Donation
4 *
5 * @package Give
6 * @subpackage Functions
7 * @copyright Copyright (c) 2016, GiveWP
8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 * @since 1.0
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Process Donation Form
19 *
20 * Handles the donation form process.
21 *
22 * @access private
23 * @since 3.16.1 Use give_maybe_safe_unserialize() on $user_info data
24 * @since 1.0
25 *
26 * @throws ReflectionException Exception Handling.
27 *
28 * @return mixed
29 */
30 function give_process_donation_form() {
31
32 // Sanitize Posted Data.
33 $post_data = give_clean( $_POST ); // WPCS: input var ok, CSRF ok.
34
35 // Check whether the form submitted via AJAX or not.
36 $is_ajax = isset( $post_data['give_ajax'] );
37
38 // Verify donation form nonce.
39 if ( ! give_verify_donation_form_nonce( $post_data['give-form-hash'], $post_data['give-form-id'] ) ) {
40 if ( $is_ajax ) {
41 /**
42 * Fires when AJAX sends back errors from the donation form.
43 *
44 * @since 1.0
45 */
46 do_action( 'give_ajax_donation_errors' );
47 give_die();
48 } else {
49 give_send_back_to_checkout();
50 }
51 }
52
53 /**
54 * Fires before processing the donation form.
55 *
56 * @since 1.0
57 */
58 do_action( 'give_pre_process_donation' );
59
60 // Validate the form $_POST data.
61 $valid_data = give_donation_form_validate_fields();
62
63 /**
64 * Fires after validating donation form fields.
65 *
66 * Allow you to hook to donation form errors.
67 *
68 * @since 1.0
69 *
70 * @param bool|array $valid_data Validate fields.
71 * @param array $deprecated Deprecated Since 2.0.2. Use $_POST instead.
72 */
73 $deprecated = $post_data;
74 do_action( 'give_checkout_error_checks', $valid_data, $deprecated );
75
76 // Process the login form.
77 if ( isset( $post_data['give_login_submit'] ) ) {
78 give_process_form_login();
79 }
80
81 // Validate the user.
82 $user = give_get_donation_form_user( $valid_data );
83
84 if ( false === $valid_data || ! $user || give_get_errors() ) {
85 if ( $is_ajax ) {
86 /**
87 * Fires when AJAX sends back errors from the donation form.
88 *
89 * @since 1.0
90 */
91 do_action( 'give_ajax_donation_errors' );
92 give_die();
93 } else {
94 return false;
95 }
96 }
97
98 // If AJAX send back success to proceed with form submission.
99 if ( $is_ajax ) {
100 echo 'success';
101 give_die();
102 }
103
104 /**
105 * Fires action after donation form field validated.
106 *
107 * @since 2.2.0
108 */
109 do_action( 'give_process_donation_after_validation' );
110
111 // Setup user information.
112 $user_info = [
113 'id' => $user['user_id'],
114 'title' => $user['user_title'],
115 'email' => $user['user_email'],
116 'first_name' => $user['user_first'],
117 'last_name' => $user['user_last'],
118 'address' => $user['address'],
119 ];
120
121 $auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
122
123 // Donation form ID.
124 $form_id = isset( $post_data['give-form-id'] ) ? absint( $post_data['give-form-id'] ) : 0;
125
126 $price = isset( $post_data['give-amount'] ) ?
127 (float) apply_filters( 'give_donation_total', give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => give_get_currency( $form_id ) ] ) ) :
128 '0.00';
129 $purchase_key = strtolower( md5( $user['user_email'] . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'give', true ) ) );
130
131 /**
132 * Update donation Purchase key.
133 *
134 * Use this filter to update default donation purchase key
135 * and add prefix in Invoice.
136 *
137 * @since 2.2.4
138 *
139 * @param string $purchase_key
140 * @param string $gateway
141 * @param string $purchase_key
142 *
143 * @return string $purchase_key
144 */
145 $purchase_key = apply_filters(
146 'give_donation_purchase_key',
147 $purchase_key,
148 $valid_data['gateway'],
149 // Use this purchase key value if you want to generate custom donation purchase key
150 // because donation purchase key editable by filters and you may get unedited donation purchase key.
151 $purchase_key
152 );
153
154 // Setup donation information.
155 $user_info = array_map('\Give\Helpers\Utils::maybeSafeUnserialize', stripslashes_deep( $user_info ));
156 $donation_data = [
157 'price' => $price,
158 'purchase_key' => $purchase_key,
159 'user_email' => $user['user_email'],
160 'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
161 'user_info' => $user_info,
162 'post_data' => $post_data,
163 'gateway' => $valid_data['gateway'],
164 'card_info' => $valid_data['cc_info'],
165 ];
166
167 // Add the user data for hooks.
168 $valid_data['user'] = $user;
169
170 /**
171 * Fires before donation form gateway.
172 *
173 * Allow you to hook to donation form before the gateway.
174 *
175 * @since 1.0
176 *
177 * @param array $post_data Array of variables passed via the HTTP POST.
178 * @param array $user_info Array containing basic user information.
179 * @param bool|array $valid_data Validate fields.
180 */
181 do_action( 'give_checkout_before_gateway', $post_data, $user_info, $valid_data );
182
183 // Sanity check for price.
184 if ( ! $donation_data['price'] ) {
185 // Revert to manual.
186 $donation_data['gateway'] = 'manual';
187 $_POST['give-gateway'] = 'manual';
188 }
189
190 /**
191 * Allow the donation data to be modified before it is sent to the gateway.
192 *
193 * @since 1.7
194 */
195 $donation_data = apply_filters( 'give_donation_data_before_gateway', $donation_data, $valid_data );
196
197 // Setup the data we're storing in the donation session.
198 $session_data = $donation_data;
199
200 // Make sure credit card numbers are never stored in sessions.
201 unset( $session_data['card_info']['card_number'] );
202 unset( $session_data['post_data']['card_number'] );
203
204 // Used for showing data to non logged-in users after donation, and for other plugins needing donation data.
205 give_set_purchase_session( $session_data );
206
207 /**
208 * Prevent PHP notices from breaking receipt display.
209 * This is specifically an issue with the Stripe SDK.
210 *
211 * @link https://github.com/impress-org/givewp/issues/5199
212 */
213 ob_start();
214 // Send info to the gateway for payment processing.
215 give_send_to_gateway( $donation_data['gateway'], $donation_data );
216 ob_get_clean();
217 give_die();
218 }
219
220 add_action( 'give_purchase', 'give_process_donation_form' );
221 add_action( 'wp_ajax_give_process_donation', 'give_process_donation_form' );
222 add_action( 'wp_ajax_nopriv_give_process_donation', 'give_process_donation_form' );
223
224 /**
225 * Verify that when a logged in user makes a donation that the email address used doesn't belong to a different customer.
226 * Note: only for internal use
227 *
228 * @see https://github.com/impress-org/give/issues/4025
229 *
230 * @since 1.7
231 * @since 2.4.2 This function runs independently instead of give_checkout_error_checks hook and also edit donor email.
232 *
233 * @param array $valid_data Validated data submitted for the donation.
234 *
235 * @return void
236 */
237 function give_check_logged_in_user_for_existing_email( &$valid_data ) {
238
239 // Verify that the email address belongs to this donor.
240 if ( is_user_logged_in() ) {
241
242 $donor = new Give_Donor( get_current_user_id(), true );
243
244 // Bailout: check if wp user is existing donor or not.
245 if ( ! $donor->id ) {
246 return;
247 }
248
249 $submitted_email = strtolower( $valid_data['user_email'] );
250
251 $donor_emails = array_map( 'strtolower', $donor->emails );
252 $email_index = array_search( $submitted_email, $donor_emails, true );
253
254 // If donor matched with email then return set formatted email from database.
255 if ( false !== $email_index ) {
256 $valid_data['user_email'] = $donor->emails[ $email_index ];
257
258 return;
259 }
260
261 // If this email address is not registered with this customer, see if it belongs to any other customer.
262 $found_donor = new Give_Donor( $submitted_email );
263
264 if ( $found_donor->id > 0 ) {
265 give_set_error(
266 'give-customer-email-exists',
267 sprintf(
268 /* translators: 1. Donor Email, 2. Submitted Email */
269 __( 'You are logged in as %1$s, and are submitting a donation as %2$s, which is an existing donor. To ensure that the email address is tied to the correct donor, please submit this donation from a logged-out browser, or choose another email address.', 'give' ),
270 $donor->email,
271 $submitted_email
272 )
273 );
274 }
275 }
276 }
277
278 /**
279 * Process the checkout login form
280 *
281 * @access private
282 * @since 1.0
283 *
284 * @return void
285 */
286 function give_process_form_login() {
287
288 $is_ajax = ! empty( $_POST['give_ajax'] ) ? give_clean( $_POST['give_ajax'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
289 $referrer = wp_get_referer();
290 $user_data = give_donation_form_validate_user_login();
291
292 if ( give_get_errors() || $user_data['user_id'] < 1 ) {
293 if ( $is_ajax ) {
294 /**
295 * Fires when AJAX sends back errors from the donation form.
296 *
297 * @since 1.0
298 */
299 ob_start();
300 do_action( 'give_ajax_donation_errors' );
301 $message = ob_get_contents();
302 ob_end_clean();
303 wp_send_json_error( $message );
304 } else {
305 wp_safe_redirect( $referrer );
306 exit;
307 }
308 }
309
310 give_log_user_in( $user_data['user_id'], $user_data['user_login'], $user_data['user_pass'] );
311
312 if ( $is_ajax ) {
313 $message = Give_Notices::print_frontend_notice(
314 sprintf(
315 /* translators: %s: user first name */
316 esc_html__( 'Welcome %s! You have successfully logged into your account.', 'give' ),
317 ( ! empty( $user_data['user_first'] ) ) ? $user_data['user_first'] : $user_data['user_login']
318 ),
319 false,
320 'success'
321 );
322
323 wp_send_json_success( $message );
324 } else {
325 wp_safe_redirect( $referrer );
326 }
327 }
328
329 add_action( 'wp_ajax_give_process_donation_login', 'give_process_form_login' );
330 add_action( 'wp_ajax_nopriv_give_process_donation_login', 'give_process_form_login' );
331
332 /**
333 * Donation Form Validate Fields.
334 *
335 * @access private
336 * @since 3.5.0 validate serialized fields
337 * @since 1.0
338 *
339 * @return bool|array
340 */
341 function give_donation_form_validate_fields() {
342
343 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
344 give_donation_form_validate_name_fields($post_data);
345
346 // Validate Honeypot First.
347 if ( ! empty( $post_data['give-honeypot'] ) ) {
348 give_set_error( 'invalid_honeypot', esc_html__( 'Honeypot field detected. Go away bad bot!', 'give' ) );
349 }
350
351 // Validate serialized fields.
352 if (give_donation_form_has_serialized_fields($post_data)) {
353 give_set_error('invalid_serialized_fields', esc_html__('Serialized fields detected. Go away!', 'give'));
354 }
355
356 // Check spam detect.
357 if (
358 isset( $post_data['action'] )
359 && give_is_spam_donation()
360 ) {
361 give_set_error( 'spam_donation', __( 'The email you are using has been flagged as one used in SPAM comments or donations by our system. Please try using a different email address or contact the site administrator if you have any questions.', 'give' ) );
362 }
363
364 // Start an array to collect valid data.
365 $valid_data = [
366 'gateway' => give_donation_form_validate_gateway(), // Gateway fallback (amount is validated here).
367 'need_new_user' => false, // New user flag.
368 'need_user_login' => false, // Login user flag.
369 'logged_user_data' => [], // Logged user collected data.
370 'new_user_data' => [], // New user collected data.
371 'login_user_data' => [], // Login user collected data.
372 'guest_user_data' => [], // Guest user collected data.
373 'cc_info' => give_donation_form_validate_cc(), // Credit card info.
374 ];
375
376 $form_id = (int) $post_data['give-form-id'];
377
378 // Validate agree to terms.
379 if ( give_is_terms_enabled( $form_id ) ) {
380 give_donation_form_validate_agree_to_terms();
381 }
382
383 if ( is_user_logged_in() ) {
384
385 // Collect logged in user data.
386 $valid_data['logged_in_user'] = give_donation_form_validate_logged_in_user();
387 } elseif (
388 isset( $post_data['give-purchase-var'] )
389 && 'needs-to-register' === $post_data['give-purchase-var']
390 && ! empty( $post_data['give_create_account'] )
391 ) {
392
393 // Set new user registration as required.
394 $valid_data['need_new_user'] = true;
395
396 // Validate new user data.
397 $valid_data['new_user_data'] = give_donation_form_validate_new_user();
398 } elseif (
399 isset( $post_data['give-purchase-var'] )
400 && 'needs-to-login' === $post_data['give-purchase-var']
401 ) {
402
403 // Set user login as required.
404 $valid_data['need_user_login'] = true;
405
406 // Validate users login info.
407 $valid_data['login_user_data'] = give_donation_form_validate_user_login();
408 } else {
409
410 // Not registering or logging in, so setup guest user data.
411 $valid_data['guest_user_data'] = give_donation_form_validate_guest_user();
412 }
413
414 // Return collected data.
415 return $valid_data;
416 }
417
418 /**
419 * Detect serialized fields.
420 *
421 * @since 3.16.2 added additional check for stripslashes_deep
422 * @since 3.14.2 add give-form-title, give_title
423 * @since 3.5.0
424 */
425 function give_donation_form_has_serialized_fields(array $post_data): bool
426 {
427 $post_data_keys = [
428 'give-form-id',
429 'give-gateway',
430 'card_name',
431 'card_number',
432 'card_cvc',
433 'card_exp_month',
434 'card_exp_year',
435 'card_address',
436 'card_address_2',
437 'card_city',
438 'card_state',
439 'billing_country',
440 'card_zip',
441 'give_email',
442 'give_first',
443 'give_last',
444 'give_user_login',
445 'give_user_pass',
446 'give-form-title',
447 'give_title',
448 ];
449
450 foreach ($post_data as $key => $value) {
451 if ( ! in_array($key, $post_data_keys, true)) {
452 continue;
453 }
454
455 if (is_serialized(stripslashes_deep($value))) {
456 return true;
457 }
458
459 if (is_serialized($value)) {
460 return true;
461 }
462 }
463
464 return false;
465 }
466
467 /**
468 * Detect spam donation.
469 *
470 * @since 1.8.14
471 *
472 * @return bool|mixed
473 */
474 function give_is_spam_donation() {
475 $spam = false;
476
477 $user_agent = (string) isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
478
479 if ( strlen( $user_agent ) < 2 ) {
480 $spam = true;
481 }
482
483 // Allow developer to customized Akismet spam detect API call and it's response.
484 return apply_filters( 'give_spam', $spam );
485 }
486
487 /**
488 * Donation Form Validate Gateway
489 *
490 * Validate the gateway and donation amount.
491 *
492 * @access private
493 * @since 1.0
494 *
495 * @return string
496 */
497 function give_donation_form_validate_gateway() {
498
499 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
500 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
501 $amount = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'] ) : 0;
502 $gateway = ! empty( $post_data['give-gateway'] ) ? $post_data['give-gateway'] : 0;
503
504 // Bailout, if payment gateway is not submitted with donation form data.
505 if ( empty( $gateway ) ) {
506
507 give_set_error( 'empty_gateway', __( 'The donation form will process with a valid payment gateway.', 'give' ) );
508
509 } elseif ( ! give_is_gateway_active( $gateway ) ) {
510
511 give_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled.', 'give' ) );
512
513 } elseif ( empty( $amount ) ) {
514
515 give_set_error( 'invalid_donation_amount', __( 'Please insert a valid donation amount.', 'give' ) );
516
517 } elseif ( ! give_verify_minimum_price( 'minimum' ) ) {
518
519 give_set_error(
520 'invalid_donation_minimum',
521 sprintf(
522 /* translators: %s: minimum donation amount */
523 __( 'This form has a minimum donation amount of %s.', 'give' ),
524 give_currency_filter(
525 give_format_amount(
526 give_get_form_minimum_price( $form_id ),
527 [
528 'sanitize' => false,
529 ]
530 )
531 )
532 )
533 );
534 } elseif ( ! give_verify_minimum_price( 'maximum' ) ) {
535
536 give_set_error(
537 'invalid_donation_maximum',
538 sprintf(
539 /* translators: %s: Maximum donation amount */
540 __( 'This form has a maximum donation amount of %s.', 'give' ),
541 give_currency_filter(
542 give_format_amount(
543 give_get_form_maximum_price( $form_id ),
544 [
545 'sanitize' => false,
546 ]
547 )
548 )
549 )
550 );
551 } // End if().
552
553 return $gateway;
554
555 }
556
557 /**
558 * Donation Form Validate Minimum or Maximum Donation Amount
559 *
560 * @access private
561 * @since 1.3.6
562 * @since 2.1 Added support for give maximum amount.
563 * @since 2.1.3 Added new filter to modify the return value.
564 *
565 * @param string $amount_range Which amount needs to verify? minimum or maximum.
566 *
567 * @return bool
568 */
569 function give_verify_minimum_price( $amount_range = 'minimum' ) {
570
571 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
572 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
573 $amount = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => give_get_currency( $form_id ) ] ) : 0;
574 $price_id = isset( $post_data['give-price-id'] ) ? absint( $post_data['give-price-id'] ) : '';
575
576 $variable_prices = give_has_variable_prices( $form_id );
577 $price_ids = array_map( 'absint', give_get_variable_price_ids( $form_id ) );
578 $verified_stat = false;
579
580 if ( $variable_prices && in_array( $price_id, $price_ids, true ) ) {
581
582 $price_level_amount = give_get_price_option_amount( $form_id, $price_id );
583
584 if ( $price_level_amount == $amount ) {
585 $verified_stat = true;
586 }
587 }
588
589 if ( ! $verified_stat ) {
590 switch ( $amount_range ) {
591 case 'minimum':
592 $verified_stat = ( give_get_form_minimum_price( $form_id ) > $amount ) ? false : true;
593 break;
594 case 'maximum':
595 $verified_stat = ( give_get_form_maximum_price( $form_id ) < $amount ) ? false : true;
596 break;
597 }
598 }
599
600 /**
601 * Filter the verify amount
602 *
603 * @since 2.1.3
604 *
605 * @param bool $verified_stat Was verification passed or not?
606 * @param string $amount_range Type of the amount.
607 * @param integer $form_id Give Donation Form ID.
608 */
609 return apply_filters( 'give_verify_minimum_maximum_price', $verified_stat, $amount_range, $form_id );
610 }
611
612 /**
613 * Donation form validate agree to "Terms and Conditions".
614 *
615 * @access private
616 * @since 1.0
617 *
618 * @return void
619 */
620 function give_donation_form_validate_agree_to_terms() {
621
622 $agree_to_terms = ! empty( $_POST['give_agree_to_terms'] ) ? give_clean( $_POST['give_agree_to_terms'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
623
624 // Proceed only, if donor agreed to terms.
625 if ( ! $agree_to_terms ) {
626
627 // User did not agree.
628 give_set_error( 'agree_to_terms', apply_filters( 'give_agree_to_terms_text', __( 'You must agree to the terms and conditions.', 'give' ) ) );
629 }
630 }
631
632 /**
633 * Donation Form Required Fields.
634 *
635 * @access private
636 * @since 1.0
637 *
638 * @param int $form_id Donation Form ID.
639 *
640 * @return array
641 */
642 function give_get_required_fields( $form_id ) {
643
644 $posted_data = give_clean( filter_input_array( INPUT_POST ) );
645 $payment_mode = give_get_chosen_gateway( $form_id );
646
647 $required_fields = [
648 'give_email' => [
649 'error_id' => 'invalid_email',
650 'error_message' => __( 'Please enter a valid email address.', 'give' ),
651 ],
652 'give_first' => [
653 'error_id' => 'invalid_first_name',
654 'error_message' => __( 'Please enter your first name.', 'give' ),
655 ],
656 ];
657
658 $name_title_prefix = give_is_name_title_prefix_required( $form_id );
659 if ( $name_title_prefix ) {
660 $required_fields['give_title'] = [
661 'error_id' => 'invalid_title',
662 'error_message' => __( 'Please enter your title.', 'give' ),
663 ];
664 }
665
666 // If credit card fields related actions exists then check for the cc fields validations.
667 if (
668 has_action( "give_{$payment_mode}_cc_form", 'give_get_cc_form' ) ||
669 has_action( 'give_cc_form', 'give_get_cc_form' )
670 ) {
671
672 // Validate card number field for empty check.
673 if (
674 isset( $posted_data['card_number'] ) &&
675 empty( $posted_data['card_number'] )
676 ) {
677 $required_fields['card_number'] = [
678 'error_id' => 'empty_card_number',
679 'error_message' => __( 'Please enter a credit card number.', 'give' ),
680 ];
681 }
682
683 // Validate card cvc field for empty check.
684 if (
685 isset( $posted_data['card_cvc'] ) &&
686 empty( $posted_data['card_cvc'] )
687 ) {
688 $required_fields['card_cvc'] = [
689 'error_id' => 'empty_card_cvc',
690 'error_message' => __( 'Please enter a credit card CVC information.', 'give' ),
691 ];
692 }
693
694 // Validate card name field for empty check.
695 if (
696 (
697 isset( $posted_data['give_validate_stripe_payment_fields'] ) &&
698 '1' === $posted_data['give_validate_stripe_payment_fields'] &&
699 isset( $posted_data['card_name'] ) &&
700 empty( $posted_data['card_name'] )
701 ) ||
702 (
703 ! isset( $posted_data['give_validate_stripe_payment_fields'] ) &&
704 isset( $posted_data['card_name'] ) &&
705 empty( $posted_data['card_name'] )
706 )
707 ) {
708 $required_fields['card_name'] = [
709 'error_id' => 'empty_card_name',
710 'error_message' => __( 'Please enter a name of your credit card account holder.', 'give' ),
711 ];
712 }
713
714 // Validate card expiry field for empty check.
715 if (
716 isset( $posted_data['card_expiry'] ) &&
717 empty( $posted_data['card_expiry'] )
718 ) {
719 $required_fields['card_expiry'] = [
720 'error_id' => 'empty_card_expiry',
721 'error_message' => __( 'Please enter a credit card expiry date.', 'give' ),
722 ];
723 }
724 }
725
726 $require_address = give_require_billing_address( $payment_mode );
727
728 if ( $require_address ) {
729 $required_fields['card_address'] = [
730 'error_id' => 'invalid_card_address',
731 'error_message' => __( 'Please enter your primary billing address.', 'give' ),
732 ];
733 $required_fields['card_zip'] = [
734 'error_id' => 'invalid_zip_code',
735 'error_message' => __( 'Please enter your zip / postal code.', 'give' ),
736 ];
737 $required_fields['card_city'] = [
738 'error_id' => 'invalid_city',
739 'error_message' => __( 'Please enter your billing city.', 'give' ),
740 ];
741 $required_fields['billing_country'] = [
742 'error_id' => 'invalid_country',
743 'error_message' => __( 'Please select your billing country.', 'give' ),
744 ];
745
746 $required_fields['card_state'] = [
747 'error_id' => 'invalid_state',
748 'error_message' => __( 'Please enter billing state / province / County.', 'give' ),
749 ];
750
751 $country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
752
753 // Check if billing country already exists.
754 if ( $country ) {
755
756 // Check if states is empty or not.
757 if ( array_key_exists( $country, give_states_not_required_country_list() ) ) {
758 // If states is empty remove the required fields of state in billing cart.
759 unset( $required_fields['card_state'] );
760 }
761
762 // Check if city is empty or not.
763 if ( array_key_exists( $country, give_city_not_required_country_list() ) ) {
764 // If states is empty remove the required fields of city in billing cart.
765 unset( $required_fields['card_city'] );
766 }
767
768 // Check if country is without post codes.
769 if ( array_key_exists( $country, give_get_country_list_without_postcodes() ) ) {
770 // If country is on the list, zip code is not required.
771 unset( $required_fields['card_zip'] );
772 }
773 }
774 } // End if().
775
776 if ( give_is_company_field_enabled( $form_id ) ) {
777 $form_option = give_get_meta( $form_id, '_give_company_field', true );
778 $global_setting = give_get_option( 'company_field' );
779
780 $is_company_field_required = false;
781
782 if ( ! empty( $form_option ) && give_is_setting_enabled( $form_option, [ 'required' ] ) ) {
783 $is_company_field_required = true;
784
785 } elseif ( 'global' === $form_option && give_is_setting_enabled( $global_setting, [ 'required' ] ) ) {
786 $is_company_field_required = true;
787
788 } elseif ( empty( $form_option ) && give_is_setting_enabled( $global_setting, [ 'required' ] ) ) {
789 $is_company_field_required = true;
790
791 }
792
793 if ( $is_company_field_required ) {
794 $required_fields['give_company_name'] = [
795 'error_id' => 'invalid_company',
796 'error_message' => __( 'Please enter Company Name.', 'give' ),
797 ];
798 }
799 }
800
801 if ( give_is_last_name_required( $form_id ) ) {
802 $required_fields['give_last'] = [
803 'error_id' => 'invalid_last_name',
804 'error_message' => __( 'Please enter your last name.', 'give' ),
805 ];
806 }
807
808 /**
809 * Filters the donation form required field.
810 *
811 * @since 1.7
812 */
813 $required_fields = apply_filters( 'give_donation_form_required_fields', $required_fields, $form_id );
814
815 return $required_fields;
816
817 }
818
819 /**
820 * Check if the Billing Address is required
821 *
822 * @since 1.0.1
823 *
824 * @param string $payment_mode Payment Mode.
825 *
826 * @return bool
827 */
828 function give_require_billing_address( $payment_mode ) {
829
830 $return = false;
831 $billing_country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
832
833 if ( $billing_country || did_action( "give_{$payment_mode}_cc_form" ) || did_action( 'give_cc_form' ) ) {
834 $return = true;
835 }
836
837 // Let payment gateways and other extensions determine if address fields should be required.
838 return apply_filters( 'give_require_billing_address', $return );
839
840 }
841
842 /**
843 * Donation Form Validate Logged In User.
844 *
845 * @access private
846 * @since 1.0
847 *
848 * @return array
849 */
850 function give_donation_form_validate_logged_in_user() {
851
852 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
853 $user_id = get_current_user_id();
854 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
855
856 // Start empty array to collect valid user data.
857 $valid_user_data = [
858
859 // Assume there will be errors.
860 'user_id' => - 1,
861 ];
862
863 // Proceed only, if valid $user_id found.
864 if ( $user_id > 0 ) {
865
866 // Get the logged in user data.
867 $user_data = get_userdata( $user_id );
868
869 // Validate Required Form Fields.
870 give_validate_required_form_fields( $form_id );
871
872 // Verify data.
873 if ( is_object( $user_data ) && $user_data->ID > 0 ) {
874 // Collected logged in user data.
875 $valid_user_data = [
876 'user_id' => $user_id,
877 'user_email' => ! empty( $post_data['give_email'] )
878 ? sanitize_email( $post_data['give_email'] )
879 : $user_data->user_email,
880 'user_first' => ! empty( $post_data['give_first'] )
881 ? $post_data['give_first']
882 : $user_data->first_name,
883 'user_last' => ! empty( $post_data['give_last'] )
884 ? $post_data['give_last']
885 : $user_data->last_name,
886 ];
887
888 // Validate essential form fields.
889 give_donation_form_validate_name_fields( $post_data );
890
891 give_check_logged_in_user_for_existing_email( $valid_user_data );
892
893 if ( ! is_email( $valid_user_data['user_email'] ) ) {
894 give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
895 }
896 } else {
897
898 // Set invalid user information error.
899 give_set_error( 'invalid_user', esc_html__( 'The user information is invalid.', 'give' ) );
900 }
901 }
902
903 // Return user data.
904 return $valid_user_data;
905 }
906
907 /**
908 * Donate Form Validate New User
909 *
910 * @access private
911 * @since 1.0
912 *
913 * @return array
914 */
915 function give_donation_form_validate_new_user() {
916 // Default user data.
917 $auto_generated_password = wp_generate_password();
918 $default_user_data = [
919 'give-form-id' => '',
920 'user_id' => - 1, // Assume there will be errors.
921 'user_first' => '',
922 'user_last' => '',
923 'give_user_login' => false,
924 'give_email' => false,
925 'give_user_pass' => $auto_generated_password,
926 'give_user_pass_confirm' => $auto_generated_password,
927 ];
928
929 // Get data.
930 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
931 $user_data = wp_parse_args( $post_data, $default_user_data );
932
933 $form_id = absint( $user_data['give-form-id'] );
934 $nonce = ! empty( $post_data['give-form-user-register-hash'] ) ? $post_data['give-form-user-register-hash'] : '';
935
936 // Validate user creation nonce.
937 if ( ! wp_verify_nonce( $nonce, "give_form_create_user_nonce_{$form_id}" ) ) {
938 give_set_error( 'invalid_nonce', __( 'We\'re unable to recognize your session. Please refresh the screen to try again; otherwise contact your website administrator for assistance.', 'give' ) );
939 }
940
941 $registering_new_user = false;
942
943 give_donation_form_validate_name_fields( $user_data );
944
945 // Start an empty array to collect valid user data.
946 $valid_user_data = [
947
948 // Assume there will be errors.
949 'user_id' => - 1,
950
951 // Get first name.
952 'user_first' => $user_data['give_first'],
953
954 // Get last name.
955 'user_last' => $user_data['give_last'],
956
957 // Get Password.
958 'user_pass' => $user_data['give_user_pass'],
959 ];
960
961 // Validate Required Form Fields.
962 give_validate_required_form_fields( $form_id );
963
964 // Set Email as Username.
965 $valid_user_data['user_login'] = $user_data['give_email'];
966
967 // Check if we have an email to verify.
968 if ( give_validate_user_email( $user_data['give_email'], $registering_new_user ) ) {
969 $valid_user_data['user_email'] = $user_data['give_email'];
970 }
971
972 return $valid_user_data;
973 }
974
975 /**
976 * Donation Form Validate User Login
977 *
978 * @access private
979 * @since 1.0
980 *
981 * @return array
982 */
983 function give_donation_form_validate_user_login() {
984
985 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
986
987 // Start an array to collect valid user data.
988 $valid_user_data = [
989
990 // Assume there will be errors.
991 'user_id' => - 1,
992 ];
993
994 // Bailout, if Username is empty.
995 if ( empty( $post_data['give_user_login'] ) ) {
996 give_set_error( 'must_log_in', __( 'Please enter your username or email to log in.', 'give' ) );
997
998 return $valid_user_data;
999 }
1000
1001 $give_user_login = strip_tags( $post_data['give_user_login'] );
1002 if ( is_email( $give_user_login ) ) {
1003 // Get the user data by email.
1004 $user_data = get_user_by( 'email', $give_user_login );
1005 } else {
1006 // Get the user data by login.
1007 $user_data = get_user_by( 'login', $give_user_login );
1008 }
1009
1010 // Check if user exists.
1011 if ( $user_data ) {
1012
1013 // Get password.
1014 $user_pass = ! empty( $post_data['give_user_pass'] ) ? $post_data['give_user_pass'] : false;
1015
1016 // Check user_pass.
1017 if ( $user_pass ) {
1018
1019 // Check if password is valid.
1020 if ( ! wp_check_password( $user_pass, $user_data->user_pass, $user_data->ID ) ) {
1021
1022 $current_page_url = site_url() . '/' . get_page_uri();
1023
1024 // Incorrect password.
1025 give_set_error(
1026 'password_incorrect',
1027 sprintf(
1028 '%1$s <a href="%2$s">%3$s</a>',
1029 __( 'The password you entered is incorrect.', 'give' ),
1030 wp_lostpassword_url( $current_page_url ),
1031 __( 'Reset Password', 'give' )
1032 )
1033 );
1034
1035 } else {
1036
1037 // Repopulate the valid user data array.
1038 $valid_user_data = [
1039 'user_id' => $user_data->ID,
1040 'user_login' => $user_data->user_login,
1041 'user_email' => $user_data->user_email,
1042 'user_first' => $user_data->first_name,
1043 'user_last' => $user_data->last_name,
1044 'user_pass' => $user_pass,
1045 ];
1046 }
1047 } else {
1048 // Empty password.
1049 give_set_error( 'password_empty', __( 'Enter a password.', 'give' ) );
1050 }
1051 } else {
1052 // No username.
1053 give_set_error( 'username_incorrect', __( 'The username you entered does not exist.', 'give' ) );
1054 } // End if().
1055
1056 return $valid_user_data;
1057 }
1058
1059 /**
1060 * Donation Form Validate Guest User
1061 *
1062 * @access private
1063 * @since 1.0
1064 *
1065 * @return array
1066 */
1067 function give_donation_form_validate_guest_user() {
1068
1069 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1070 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
1071
1072 // Start an array to collect valid user data.
1073 $valid_user_data = [
1074 // Set a default id for guests.
1075 'user_id' => 0,
1076 ];
1077
1078 // Validate name fields.
1079 give_donation_form_validate_name_fields( $post_data );
1080
1081 // Validate Required Form Fields.
1082 give_validate_required_form_fields( $form_id );
1083
1084 // Get the guest email.
1085 $guest_email = ! empty( $post_data['give_email'] ) ? $post_data['give_email'] : false;
1086
1087 // Check email.
1088 if ( $guest_email && strlen( $guest_email ) > 0 ) {
1089
1090 // Validate email.
1091 if ( ! is_email( $guest_email ) ) {
1092
1093 // Invalid email.
1094 give_set_error( 'email_invalid', __( 'Invalid email.', 'give' ) );
1095
1096 } else {
1097
1098 // All is good to go.
1099 $valid_user_data['user_email'] = $guest_email;
1100
1101 // Get user_id from donor if exist.
1102 $donor = new Give_Donor( $guest_email );
1103
1104 if ( $donor->id ) {
1105 $donor_email_index = array_search(
1106 strtolower( $guest_email ),
1107 array_map( 'strtolower', $donor->emails ),
1108 true
1109 );
1110
1111 $valid_user_data['user_id'] = $donor->user_id;
1112
1113 // Set email to original format.
1114 // @see https://github.com/impress-org/give/issues/4025
1115 $valid_user_data['user_email'] = $donor->emails[ $donor_email_index ];
1116 }
1117 }
1118 } else {
1119 // No email.
1120 give_set_error( 'email_empty', __( 'Enter an email.', 'give' ) );
1121 }
1122
1123 return $valid_user_data;
1124 }
1125
1126 /**
1127 * Register And Login New User
1128 *
1129 * @param array $user_data User Data.
1130 *
1131 * @access private
1132 * @since 1.0
1133 *
1134 * @return integer
1135 */
1136 function give_register_and_login_new_user( $user_data = [] ) {
1137 // Verify the array.
1138 if ( empty( $user_data ) ) {
1139 return - 1;
1140 }
1141
1142 if ( give_get_errors() ) {
1143 return - 1;
1144 }
1145
1146 $user_args = apply_filters(
1147 'give_insert_user_args',
1148 [
1149 'user_login' => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
1150 'user_pass' => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
1151 'user_email' => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
1152 'first_name' => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
1153 'last_name' => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
1154 'user_registered' => date( 'Y-m-d H:i:s' ),
1155 'role' => give_get_option( 'donor_default_user_role', 'give_donor' ),
1156 ],
1157 $user_data
1158 );
1159
1160 // Insert new user.
1161 $user_id = wp_insert_user( $user_args );
1162
1163 // Validate inserted user.
1164 if ( is_wp_error( $user_id ) ) {
1165 return - 1;
1166 }
1167
1168 // Allow themes and plugins to filter the user data.
1169 $user_data = apply_filters( 'give_insert_user_data', $user_data, $user_args );
1170
1171 /**
1172 * Fires after inserting user.
1173 *
1174 * @since 1.0
1175 *
1176 * @param int $user_id User id.
1177 * @param array $user_data Array containing user data.
1178 */
1179 do_action( 'give_insert_user', $user_id, $user_data );
1180
1181 /**
1182 * Filter allow user to alter if user when to login or not when user is register for the first time.
1183 *
1184 * @since 1.8.13
1185 *
1186 * return bool True if login with registration and False if only want to register.
1187 */
1188 if ( true === (bool) apply_filters( 'give_log_user_in_on_register', true ) ) {
1189 // Login new user.
1190 give_log_user_in( $user_id, $user_data['user_login'], $user_data['user_pass'] );
1191 }
1192
1193 // Return user id.
1194 return $user_id;
1195 }
1196
1197 /**
1198 * Get Donation Form User
1199 *
1200 * @since 1.0
1201 * @since 2.17.1 Do not run validation check for ajax request expect donation validation ajax request.
1202 *
1203 * @param array $valid_data Valid Data.
1204 *
1205 * @access private
1206 * @return array|bool
1207 */
1208 function give_get_donation_form_user( $valid_data = [] ) {
1209 // Initialize user.
1210 $user = false;
1211 $post_data = give_clean($_POST); // WPCS: input var ok, sanitization ok, CSRF ok.
1212 $is_validating_donation_form_on_ajax = ! empty($_POST['give_ajax']) ? $post_data['give_ajax'] : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
1213
1214 if ( $is_validating_donation_form_on_ajax ) {
1215 // Do not create or login the user during the ajax submission (check for errors only).
1216 return true;
1217 } elseif ( is_user_logged_in() ) {
1218 // Set the valid user as the logged in collected data.
1219 $user = $valid_data['logged_in_user'];
1220 } elseif ( true === $valid_data['need_new_user'] || true === $valid_data['need_user_login'] ) {
1221 // New user registration.
1222 if ( true === $valid_data['need_new_user'] ) {
1223 // Set user.
1224 $user = $valid_data['new_user_data'];
1225
1226 // Register and login new user.
1227 $user['user_id'] = give_register_and_login_new_user($user);
1228 } elseif ( true === $valid_data['need_user_login'] ) {
1229 /**
1230 * The login form is now processed in the give_process_donation_login() function.
1231 * This is still here for backwards compatibility.
1232 * This also allows the old login process to still work if a user removes the checkout login submit button.
1233 *
1234 * This also ensures that the donor is logged in correctly if they click "Donation" instead of submitting the login form, meaning the donor is logged in during the donation process.
1235 */
1236 $user = $valid_data['login_user_data'];
1237
1238 // Login user.
1239 give_log_user_in( $user['user_id'], $user['user_login'], $user['user_pass'] );
1240 }
1241 } // End if().
1242
1243 // Check guest checkout.
1244 if ( false === $user && false === give_logged_in_only( $post_data['give-form-id'] ) ) {
1245
1246 // Set user.
1247 $user = $valid_data['guest_user_data'];
1248 }
1249
1250 // Verify we have an user.
1251 if ( false === $user || empty( $user ) ) {
1252 return false;
1253 }
1254
1255 // Get user first name.
1256 if ( ! isset( $user['user_first'] ) || strlen( trim( $user['user_first'] ) ) < 1 ) {
1257 $user['user_first'] = isset( $post_data['give_first'] ) ? strip_tags( trim( $post_data['give_first'] ) ) : '';
1258 }
1259
1260 // Get user last name.
1261 if ( ! isset( $user['user_last'] ) || strlen( trim( $user['user_last'] ) ) < 1 ) {
1262 $user['user_last'] = isset( $post_data['give_last'] ) ? strip_tags( trim( $post_data['give_last'] ) ) : '';
1263 }
1264
1265 // Add Title Prefix to user information.
1266 if ( empty( $user['user_title'] ) || strlen( trim( $user['user_title'] ) ) < 1 ) {
1267 $user['user_title'] = ! empty( $post_data['give_title'] ) ? strip_tags( trim( $post_data['give_title'] ) ) : '';
1268 }
1269
1270 // Get the user's billing address details.
1271 $user['address'] = [];
1272 $user['address']['line1'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : false;
1273 $user['address']['line2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : false;
1274 $user['address']['city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : false;
1275 $user['address']['state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : false;
1276 $user['address']['zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : false;
1277 $user['address']['country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : false;
1278
1279 if ( empty( $user['address']['country'] ) ) {
1280 $user['address'] = false;
1281 } // End if().
1282
1283 // Return valid user.
1284 return $user;
1285 }
1286
1287 /**
1288 * Validates the credit card info.
1289 *
1290 * @access private
1291 * @since 1.0
1292 *
1293 * @return array
1294 */
1295 function give_donation_form_validate_cc() {
1296
1297 $card_data = give_get_donation_cc_info();
1298
1299 // Validate the card zip.
1300 if ( ! empty( $card_data['card_zip'] ) ) {
1301 if ( ! give_donation_form_validate_cc_zip( $card_data['card_zip'], $card_data['card_country'] ) ) {
1302 give_set_error( 'invalid_cc_zip', __( 'The zip / postal code you entered for your billing address is invalid.', 'give' ) );
1303 }
1304 }
1305
1306 // Ensure no spaces.
1307 if ( ! empty( $card_data['card_number'] ) ) {
1308 $card_data['card_number'] = str_replace( '+', '', $card_data['card_number'] ); // no "+" signs.
1309 $card_data['card_number'] = str_replace( ' ', '', $card_data['card_number'] ); // No spaces.
1310 }
1311
1312 // This should validate card numbers at some point too.
1313 return $card_data;
1314 }
1315
1316 /**
1317 * Get credit card info.
1318 *
1319 * @access private
1320 * @since 1.0
1321 *
1322 * @return array
1323 */
1324 function give_get_donation_cc_info() {
1325
1326 // Sanitize the values submitted with donation form.
1327 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1328
1329 $cc_info = [];
1330 $cc_info['card_name'] = ! empty( $post_data['card_name'] ) ? $post_data['card_name'] : '';
1331 $cc_info['card_number'] = ! empty( $post_data['card_number'] ) ? $post_data['card_number'] : '';
1332 $cc_info['card_cvc'] = ! empty( $post_data['card_cvc'] ) ? $post_data['card_cvc'] : '';
1333 $cc_info['card_exp_month'] = ! empty( $post_data['card_exp_month'] ) ? $post_data['card_exp_month'] : '';
1334 $cc_info['card_exp_year'] = ! empty( $post_data['card_exp_year'] ) ? $post_data['card_exp_year'] : '';
1335 $cc_info['card_address'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : '';
1336 $cc_info['card_address_2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : '';
1337 $cc_info['card_city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : '';
1338 $cc_info['card_state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : '';
1339 $cc_info['card_country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : '';
1340 $cc_info['card_zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : '';
1341
1342 // Return cc info.
1343 return $cc_info;
1344 }
1345
1346 /**
1347 * Validate zip code based on country code
1348 *
1349 * @since 1.0
1350 *
1351 * @param int $zip ZIP Code.
1352 * @param string $country_code Country Code.
1353 *
1354 * @return bool|mixed
1355 */
1356 function give_donation_form_validate_cc_zip( $zip = 0, $country_code = '' ) {
1357 $ret = false;
1358
1359 if ( empty( $zip ) || empty( $country_code ) ) {
1360 return $ret;
1361 }
1362
1363 $country_code = strtoupper( $country_code );
1364
1365 $zip_regex = [
1366 'AD' => 'AD\d{3}',
1367 'AM' => '(37)?\d{4}',
1368 'AR' => '^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$',
1369 'AS' => '96799',
1370 'AT' => '\d{4}',
1371 'AU' => '^(0[289][0-9]{2})|([1345689][0-9]{3})|(2[0-8][0-9]{2})|(290[0-9])|(291[0-4])|(7[0-4][0-9]{2})|(7[8-9][0-9]{2})$',
1372 'AX' => '22\d{3}',
1373 'AZ' => '\d{4}',
1374 'BA' => '\d{5}',
1375 'BB' => '(BB\d{5})?',
1376 'BD' => '\d{4}',
1377 'BE' => '^[1-9]{1}[0-9]{3}$',
1378 'BG' => '\d{4}',
1379 'BH' => '((1[0-2]|[2-9])\d{2})?',
1380 'BM' => '[A-Z]{2}[ ]?[A-Z0-9]{2}',
1381 'BN' => '[A-Z]{2}[ ]?\d{4}',
1382 'BR' => '\d{5}[\-]?\d{3}',
1383 'BY' => '\d{6}',
1384 'CA' => '^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$',
1385 'CC' => '6799',
1386 'CH' => '^[1-9][0-9][0-9][0-9]$',
1387 'CK' => '\d{4}',
1388 'CL' => '\d{7}',
1389 'CN' => '\d{6}',
1390 'CR' => '\d{4,5}|\d{3}-\d{4}',
1391 'CS' => '\d{5}',
1392 'CV' => '\d{4}',
1393 'CX' => '6798',
1394 'CY' => '\d{4}',
1395 'CZ' => '\d{3}[ ]?\d{2}',
1396 'DE' => '\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b',
1397 'DK' => '^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$',
1398 'DO' => '\d{5}',
1399 'DZ' => '\d{5}',
1400 'EC' => '([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?',
1401 'EE' => '\d{5}',
1402 'EG' => '\d{5}',
1403 'ES' => '^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$',
1404 'ET' => '\d{4}',
1405 'FI' => '\d{5}',
1406 'FK' => 'FIQQ 1ZZ',
1407 'FM' => '(9694[1-4])([ \-]\d{4})?',
1408 'FO' => '\d{3}',
1409 'FR' => '^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$',
1410 'GE' => '\d{4}',
1411 'GF' => '9[78]3\d{2}',
1412 'GL' => '39\d{2}',
1413 'GN' => '\d{3}',
1414 'GP' => '9[78][01]\d{2}',
1415 'GR' => '\d{3}[ ]?\d{2}',
1416 'GS' => 'SIQQ 1ZZ',
1417 'GT' => '\d{5}',
1418 'GU' => '969[123]\d([ \-]\d{4})?',
1419 'GW' => '\d{4}',
1420 'HM' => '\d{4}',
1421 'HN' => '(?:\d{5})?',
1422 'HR' => '\d{5}',
1423 'HT' => '\d{4}',
1424 'HU' => '\d{4}',
1425 'ID' => '\d{5}',
1426 'IE' => '((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?',
1427 'IL' => '\d{5}',
1428 'IN' => '^[1-9][0-9][0-9][0-9][0-9][0-9]$', // India.
1429 'IO' => 'BBND 1ZZ',
1430 'IQ' => '\d{5}',
1431 'IS' => '\d{3}',
1432 'IT' => '^(V-|I-)?[0-9]{5}$',
1433 'JO' => '\d{5}',
1434 'JP' => '\d{3}-\d{4}',
1435 'KE' => '\d{5}',
1436 'KG' => '\d{6}',
1437 'KH' => '\d{5}',
1438 'KR' => '\d{5}',
1439 'KW' => '\d{5}',
1440 'KZ' => '\d{6}',
1441 'LA' => '\d{5}',
1442 'LB' => '(\d{4}([ ]?\d{4})?)?',
1443 'LI' => '(948[5-9])|(949[0-7])',
1444 'LK' => '\d{5}',
1445 'LR' => '\d{4}',
1446 'LS' => '\d{3}',
1447 'LT' => '\d{5}',
1448 'LU' => '\d{4}',
1449 'LV' => '\d{4}',
1450 'MA' => '\d{5}',
1451 'MC' => '980\d{2}',
1452 'MD' => '\d{4}',
1453 'ME' => '8\d{4}',
1454 'MG' => '\d{3}',
1455 'MH' => '969[67]\d([ \-]\d{4})?',
1456 'MK' => '\d{4}',
1457 'MN' => '\d{6}',
1458 'MP' => '9695[012]([ \-]\d{4})?',
1459 'MQ' => '9[78]2\d{2}',
1460 'MT' => '[A-Z]{3}[ ]?\d{2,4}',
1461 'MU' => '(\d{3}[A-Z]{2}\d{3})?',
1462 'MV' => '\d{5}',
1463 'MX' => '\d{5}',
1464 'MY' => '\d{5}',
1465 'NC' => '988\d{2}',
1466 'NE' => '\d{4}',
1467 'NF' => '2899',
1468 'NG' => '(\d{6})?',
1469 'NI' => '((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?',
1470 'NL' => '^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$',
1471 'NO' => '\d{4}',
1472 'NP' => '\d{5}',
1473 'NZ' => '\d{4}',
1474 'OM' => '(PC )?\d{3}',
1475 'PF' => '987\d{2}',
1476 'PG' => '\d{3}',
1477 'PH' => '\d{4}',
1478 'PK' => '\d{5}',
1479 'PL' => '\d{2}-\d{3}',
1480 'PM' => '9[78]5\d{2}',
1481 'PN' => 'PCRN 1ZZ',
1482 'PR' => '00[679]\d{2}([ \-]\d{4})?',
1483 'PT' => '\d{4}([\-]\d{3})?',
1484 'PW' => '96940',
1485 'PY' => '\d{4}',
1486 'RE' => '9[78]4\d{2}',
1487 'RO' => '\d{6}',
1488 'RS' => '\d{5}',
1489 'RU' => '\d{6}',
1490 'SA' => '\d{5}',
1491 'SE' => '^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$',
1492 'SG' => '\d{6}',
1493 'SH' => '(ASCN|STHL) 1ZZ',
1494 'SI' => '\d{4}',
1495 'SJ' => '\d{4}',
1496 'SK' => '\d{3}[ ]?\d{2}',
1497 'SM' => '4789\d',
1498 'SN' => '\d{5}',
1499 'SO' => '\d{5}',
1500 'SZ' => '[HLMS]\d{3}',
1501 'TC' => 'TKCA 1ZZ',
1502 'TH' => '\d{5}',
1503 'TJ' => '\d{6}',
1504 'TM' => '\d{6}',
1505 'TN' => '\d{4}',
1506 'TR' => '\d{5}',
1507 'TW' => '\d{3}(\d{2})?',
1508 'UA' => '\d{5}',
1509 'UK' => '^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$',
1510 'US' => '^\d{5}([\-]?\d{4})?$',
1511 'UY' => '\d{5}',
1512 'UZ' => '\d{6}',
1513 'VA' => '00120',
1514 'VE' => '\d{4}',
1515 'VI' => '008(([0-4]\d)|(5[01]))([ \-]\d{4})?',
1516 'WF' => '986\d{2}',
1517 'YT' => '976\d{2}',
1518 'YU' => '\d{5}',
1519 'ZA' => '\d{4}',
1520 'ZM' => '\d{5}',
1521 ];
1522
1523 if ( ! isset( $zip_regex[ $country_code ] ) || preg_match( '/' . $zip_regex[ $country_code ] . '/i', $zip ) ) {
1524 $ret = true;
1525 }
1526
1527 return apply_filters( 'give_is_zip_valid', $ret, $zip, $country_code );
1528 }
1529
1530 /**
1531 * Validate donation amount and auto set correct donation level id on basis of amount.
1532 *
1533 * Note: If amount does not match to donation level amount then level id will be auto select to first match level id on basis of amount.
1534 *
1535 * @param array $valid_data List of Valid Data.
1536 *
1537 * @return bool
1538 */
1539 function give_validate_donation_amount( $valid_data ) {
1540
1541 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1542
1543 /* @var Give_Donate_Form $form */
1544 $form = new Give_Donate_Form( $post_data['give-form-id'] );
1545
1546 // Get the form currency.
1547 $form_currency = give_get_currency( $post_data['give-form-id'] );
1548
1549 $donation_level_matched = false;
1550
1551 if ( $form->is_set_type_donation_form() ) {
1552
1553 // Sanitize donation amount.
1554 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => $form_currency ] );
1555
1556 // Backward compatibility.
1557 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1558 $post_data['give-price-id'] = 'custom';
1559 }
1560
1561 $donation_level_matched = true;
1562
1563 } elseif ( $form->is_multi_type_donation_form() ) {
1564
1565 $variable_prices = $form->get_prices();
1566
1567 // Bailout.
1568 if ( ! $variable_prices ) {
1569 return false;
1570 }
1571
1572 // Sanitize donation amount.
1573 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => $form_currency ] );
1574 $variable_price_option_amount = give_maybe_sanitize_amount( give_get_price_option_amount( $post_data['give-form-id'], $post_data['give-price-id'] ), [ 'currency' => $form_currency ] );
1575 $new_price_id = '';
1576
1577 if ( $post_data['give-amount'] === $variable_price_option_amount ) {
1578 return true;
1579 }
1580
1581 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1582 $new_price_id = 'custom';
1583 } else {
1584
1585 // Find correct donation level from all donation levels.
1586 foreach ( $variable_prices as $variable_price ) {
1587
1588 // Sanitize level amount.
1589 $variable_price['_give_amount'] = give_maybe_sanitize_amount( $variable_price['_give_amount'] );
1590
1591 // Set first match donation level ID.
1592 if ( $post_data['give-amount'] === $variable_price['_give_amount'] ) {
1593 $new_price_id = $variable_price['_give_id']['level_id'];
1594 break;
1595 }
1596 }
1597 }
1598
1599 // If donation amount is not find in donation levels then check if form has custom donation feature enable or not.
1600 // If yes then set price id to custom if amount is greater then custom minimum amount (if any).
1601 if ( $post_data['give-price-id'] === $new_price_id ) {
1602 $donation_level_matched = true;
1603 }
1604 } // End if().
1605
1606 if ( ! $donation_level_matched ) {
1607 give_set_error(
1608 'invalid_donation_amount',
1609 sprintf(
1610 /* translators: %s: invalid donation amount */
1611 __( 'Donation amount %s is invalid.', 'give' ),
1612 give_currency_filter(
1613 give_format_amount( $post_data['give-amount'], [ 'sanitize' => false ] )
1614 )
1615 )
1616 );
1617 }
1618 }
1619
1620 add_action( 'give_checkout_error_checks', 'give_validate_donation_amount', 10, 1 );
1621
1622 /**
1623 * Validate Required Form Fields.
1624 *
1625 * @param int $form_id Form ID.
1626 *
1627 * @since 2.0
1628 */
1629 function give_validate_required_form_fields( $form_id ) {
1630 // Sanitize values submitted with donation form.
1631 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1632 $requiredFormFields = give_get_required_fields( $form_id );
1633
1634 // Loop through required fields and show error messages.
1635 foreach ( $requiredFormFields as $field_name => $value ) {
1636 if ( empty( $post_data[ $field_name ] ) ) {
1637 give_set_error( $value['error_id'], $value['error_message'] );
1638 }
1639 }
1640 }
1641
1642 /**
1643 * Validates and checks if name fields are valid or not.
1644 *
1645 * @param array $post_data List of post data.
1646 *
1647 * @since 3.16.3 Add additional validations for name title prefix field
1648 * @since 2.1
1649 *
1650 * @return void
1651 */
1652 function give_donation_form_validate_name_fields( $post_data ) {
1653
1654 $formId = absint( $post_data['give-form-id'] );
1655
1656 if (!give_is_name_title_prefix_enabled($formId) && isset($post_data['give_title'])) {
1657 give_set_error( 'disabled_name_title', esc_html__( 'The name title prefix field is not enabled.', 'give' ) );
1658 }
1659
1660 if (give_is_name_title_prefix_enabled($formId) && isset($post_data['give_title']) && !in_array($post_data['give_title'], array_values(give_get_name_title_prefixes($formId)))) {
1661 give_set_error( 'invalid_name_title', esc_html__( 'The name title prefix field is not valid.', 'give' ) );
1662 }
1663
1664 $is_alpha_first_name = ( ! is_email( $post_data['give_first'] ) && ! preg_match( '~[0-9]~', $post_data['give_first'] ) );
1665 $is_alpha_last_name = ( ! is_email( $post_data['give_last'] ) && ! preg_match( '~[0-9]~', $post_data['give_last'] ) );
1666 $is_alpha_title = ( ! is_email( $post_data['give_title'] ) && ! preg_match( '~[0-9]~', $post_data['give_title'] ) );
1667
1668 if (!$is_alpha_first_name || ( ! empty( $post_data['give_last'] ) && ! $is_alpha_last_name) || ( ! empty( $post_data['give_title'] ) && ! $is_alpha_title) ) {
1669 give_set_error( 'invalid_name', esc_html__( 'The First Name and Last Name fields cannot contain an email address or numbers.', 'give' ) );
1670 }
1671 }
1672