PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.16.2
GiveWP – Donation Plugin and Fundraising Platform v3.16.2
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 3 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 2 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 1 year 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 3 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 6 years ago shortcodes.php 1 year ago template-functions.php 4 years ago user-functions.php 3 years ago
process-donation.php
1659 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
345 // Validate Honeypot First.
346 if ( ! empty( $post_data['give-honeypot'] ) ) {
347 give_set_error( 'invalid_honeypot', esc_html__( 'Honeypot field detected. Go away bad bot!', 'give' ) );
348 }
349
350 // Validate serialized fields.
351 if (give_donation_form_has_serialized_fields($post_data)) {
352 give_set_error('invalid_serialized_fields', esc_html__('Serialized fields detected. Go away!', 'give'));
353 }
354
355 // Check spam detect.
356 if (
357 isset( $post_data['action'] )
358 && give_is_spam_donation()
359 ) {
360 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' ) );
361 }
362
363 // Start an array to collect valid data.
364 $valid_data = [
365 'gateway' => give_donation_form_validate_gateway(), // Gateway fallback (amount is validated here).
366 'need_new_user' => false, // New user flag.
367 'need_user_login' => false, // Login user flag.
368 'logged_user_data' => [], // Logged user collected data.
369 'new_user_data' => [], // New user collected data.
370 'login_user_data' => [], // Login user collected data.
371 'guest_user_data' => [], // Guest user collected data.
372 'cc_info' => give_donation_form_validate_cc(), // Credit card info.
373 ];
374
375 $form_id = (int) $post_data['give-form-id'];
376
377 // Validate agree to terms.
378 if ( give_is_terms_enabled( $form_id ) ) {
379 give_donation_form_validate_agree_to_terms();
380 }
381
382 if ( is_user_logged_in() ) {
383
384 // Collect logged in user data.
385 $valid_data['logged_in_user'] = give_donation_form_validate_logged_in_user();
386 } elseif (
387 isset( $post_data['give-purchase-var'] )
388 && 'needs-to-register' === $post_data['give-purchase-var']
389 && ! empty( $post_data['give_create_account'] )
390 ) {
391
392 // Set new user registration as required.
393 $valid_data['need_new_user'] = true;
394
395 // Validate new user data.
396 $valid_data['new_user_data'] = give_donation_form_validate_new_user();
397 } elseif (
398 isset( $post_data['give-purchase-var'] )
399 && 'needs-to-login' === $post_data['give-purchase-var']
400 ) {
401
402 // Set user login as required.
403 $valid_data['need_user_login'] = true;
404
405 // Validate users login info.
406 $valid_data['login_user_data'] = give_donation_form_validate_user_login();
407 } else {
408
409 // Not registering or logging in, so setup guest user data.
410 $valid_data['guest_user_data'] = give_donation_form_validate_guest_user();
411 }
412
413 // Return collected data.
414 return $valid_data;
415 }
416
417 /**
418 * Detect serialized fields.
419 *
420 * @since 3.16.2 added additional check for stripslashes_deep
421 * @since 3.14.2 add give-form-title, give_title
422 * @since 3.5.0
423 */
424 function give_donation_form_has_serialized_fields(array $post_data): bool
425 {
426 $post_data_keys = [
427 'give-form-id',
428 'give-gateway',
429 'card_name',
430 'card_number',
431 'card_cvc',
432 'card_exp_month',
433 'card_exp_year',
434 'card_address',
435 'card_address_2',
436 'card_city',
437 'card_state',
438 'billing_country',
439 'card_zip',
440 'give_email',
441 'give_first',
442 'give_last',
443 'give_user_login',
444 'give_user_pass',
445 'give-form-title',
446 'give_title',
447 ];
448
449 foreach ($post_data as $key => $value) {
450 if ( ! in_array($key, $post_data_keys, true)) {
451 continue;
452 }
453
454 if (is_serialized(stripslashes_deep($value))) {
455 return true;
456 }
457
458 if (is_serialized($value)) {
459 return true;
460 }
461 }
462
463 return false;
464 }
465
466 /**
467 * Detect spam donation.
468 *
469 * @since 1.8.14
470 *
471 * @return bool|mixed
472 */
473 function give_is_spam_donation() {
474 $spam = false;
475
476 $user_agent = (string) isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
477
478 if ( strlen( $user_agent ) < 2 ) {
479 $spam = true;
480 }
481
482 // Allow developer to customized Akismet spam detect API call and it's response.
483 return apply_filters( 'give_spam', $spam );
484 }
485
486 /**
487 * Donation Form Validate Gateway
488 *
489 * Validate the gateway and donation amount.
490 *
491 * @access private
492 * @since 1.0
493 *
494 * @return string
495 */
496 function give_donation_form_validate_gateway() {
497
498 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
499 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
500 $amount = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'] ) : 0;
501 $gateway = ! empty( $post_data['give-gateway'] ) ? $post_data['give-gateway'] : 0;
502
503 // Bailout, if payment gateway is not submitted with donation form data.
504 if ( empty( $gateway ) ) {
505
506 give_set_error( 'empty_gateway', __( 'The donation form will process with a valid payment gateway.', 'give' ) );
507
508 } elseif ( ! give_is_gateway_active( $gateway ) ) {
509
510 give_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled.', 'give' ) );
511
512 } elseif ( empty( $amount ) ) {
513
514 give_set_error( 'invalid_donation_amount', __( 'Please insert a valid donation amount.', 'give' ) );
515
516 } elseif ( ! give_verify_minimum_price( 'minimum' ) ) {
517
518 give_set_error(
519 'invalid_donation_minimum',
520 sprintf(
521 /* translators: %s: minimum donation amount */
522 __( 'This form has a minimum donation amount of %s.', 'give' ),
523 give_currency_filter(
524 give_format_amount(
525 give_get_form_minimum_price( $form_id ),
526 [
527 'sanitize' => false,
528 ]
529 )
530 )
531 )
532 );
533 } elseif ( ! give_verify_minimum_price( 'maximum' ) ) {
534
535 give_set_error(
536 'invalid_donation_maximum',
537 sprintf(
538 /* translators: %s: Maximum donation amount */
539 __( 'This form has a maximum donation amount of %s.', 'give' ),
540 give_currency_filter(
541 give_format_amount(
542 give_get_form_maximum_price( $form_id ),
543 [
544 'sanitize' => false,
545 ]
546 )
547 )
548 )
549 );
550 } // End if().
551
552 return $gateway;
553
554 }
555
556 /**
557 * Donation Form Validate Minimum or Maximum Donation Amount
558 *
559 * @access private
560 * @since 1.3.6
561 * @since 2.1 Added support for give maximum amount.
562 * @since 2.1.3 Added new filter to modify the return value.
563 *
564 * @param string $amount_range Which amount needs to verify? minimum or maximum.
565 *
566 * @return bool
567 */
568 function give_verify_minimum_price( $amount_range = 'minimum' ) {
569
570 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
571 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
572 $amount = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => give_get_currency( $form_id ) ] ) : 0;
573 $price_id = isset( $post_data['give-price-id'] ) ? absint( $post_data['give-price-id'] ) : '';
574
575 $variable_prices = give_has_variable_prices( $form_id );
576 $price_ids = array_map( 'absint', give_get_variable_price_ids( $form_id ) );
577 $verified_stat = false;
578
579 if ( $variable_prices && in_array( $price_id, $price_ids, true ) ) {
580
581 $price_level_amount = give_get_price_option_amount( $form_id, $price_id );
582
583 if ( $price_level_amount == $amount ) {
584 $verified_stat = true;
585 }
586 }
587
588 if ( ! $verified_stat ) {
589 switch ( $amount_range ) {
590 case 'minimum':
591 $verified_stat = ( give_get_form_minimum_price( $form_id ) > $amount ) ? false : true;
592 break;
593 case 'maximum':
594 $verified_stat = ( give_get_form_maximum_price( $form_id ) < $amount ) ? false : true;
595 break;
596 }
597 }
598
599 /**
600 * Filter the verify amount
601 *
602 * @since 2.1.3
603 *
604 * @param bool $verified_stat Was verification passed or not?
605 * @param string $amount_range Type of the amount.
606 * @param integer $form_id Give Donation Form ID.
607 */
608 return apply_filters( 'give_verify_minimum_maximum_price', $verified_stat, $amount_range, $form_id );
609 }
610
611 /**
612 * Donation form validate agree to "Terms and Conditions".
613 *
614 * @access private
615 * @since 1.0
616 *
617 * @return void
618 */
619 function give_donation_form_validate_agree_to_terms() {
620
621 $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.
622
623 // Proceed only, if donor agreed to terms.
624 if ( ! $agree_to_terms ) {
625
626 // User did not agree.
627 give_set_error( 'agree_to_terms', apply_filters( 'give_agree_to_terms_text', __( 'You must agree to the terms and conditions.', 'give' ) ) );
628 }
629 }
630
631 /**
632 * Donation Form Required Fields.
633 *
634 * @access private
635 * @since 1.0
636 *
637 * @param int $form_id Donation Form ID.
638 *
639 * @return array
640 */
641 function give_get_required_fields( $form_id ) {
642
643 $posted_data = give_clean( filter_input_array( INPUT_POST ) );
644 $payment_mode = give_get_chosen_gateway( $form_id );
645
646 $required_fields = [
647 'give_email' => [
648 'error_id' => 'invalid_email',
649 'error_message' => __( 'Please enter a valid email address.', 'give' ),
650 ],
651 'give_first' => [
652 'error_id' => 'invalid_first_name',
653 'error_message' => __( 'Please enter your first name.', 'give' ),
654 ],
655 ];
656
657 $name_title_prefix = give_is_name_title_prefix_required( $form_id );
658 if ( $name_title_prefix ) {
659 $required_fields['give_title'] = [
660 'error_id' => 'invalid_title',
661 'error_message' => __( 'Please enter your title.', 'give' ),
662 ];
663 }
664
665 // If credit card fields related actions exists then check for the cc fields validations.
666 if (
667 has_action( "give_{$payment_mode}_cc_form", 'give_get_cc_form' ) ||
668 has_action( 'give_cc_form', 'give_get_cc_form' )
669 ) {
670
671 // Validate card number field for empty check.
672 if (
673 isset( $posted_data['card_number'] ) &&
674 empty( $posted_data['card_number'] )
675 ) {
676 $required_fields['card_number'] = [
677 'error_id' => 'empty_card_number',
678 'error_message' => __( 'Please enter a credit card number.', 'give' ),
679 ];
680 }
681
682 // Validate card cvc field for empty check.
683 if (
684 isset( $posted_data['card_cvc'] ) &&
685 empty( $posted_data['card_cvc'] )
686 ) {
687 $required_fields['card_cvc'] = [
688 'error_id' => 'empty_card_cvc',
689 'error_message' => __( 'Please enter a credit card CVC information.', 'give' ),
690 ];
691 }
692
693 // Validate card name field for empty check.
694 if (
695 (
696 isset( $posted_data['give_validate_stripe_payment_fields'] ) &&
697 '1' === $posted_data['give_validate_stripe_payment_fields'] &&
698 isset( $posted_data['card_name'] ) &&
699 empty( $posted_data['card_name'] )
700 ) ||
701 (
702 ! isset( $posted_data['give_validate_stripe_payment_fields'] ) &&
703 isset( $posted_data['card_name'] ) &&
704 empty( $posted_data['card_name'] )
705 )
706 ) {
707 $required_fields['card_name'] = [
708 'error_id' => 'empty_card_name',
709 'error_message' => __( 'Please enter a name of your credit card account holder.', 'give' ),
710 ];
711 }
712
713 // Validate card expiry field for empty check.
714 if (
715 isset( $posted_data['card_expiry'] ) &&
716 empty( $posted_data['card_expiry'] )
717 ) {
718 $required_fields['card_expiry'] = [
719 'error_id' => 'empty_card_expiry',
720 'error_message' => __( 'Please enter a credit card expiry date.', 'give' ),
721 ];
722 }
723 }
724
725 $require_address = give_require_billing_address( $payment_mode );
726
727 if ( $require_address ) {
728 $required_fields['card_address'] = [
729 'error_id' => 'invalid_card_address',
730 'error_message' => __( 'Please enter your primary billing address.', 'give' ),
731 ];
732 $required_fields['card_zip'] = [
733 'error_id' => 'invalid_zip_code',
734 'error_message' => __( 'Please enter your zip / postal code.', 'give' ),
735 ];
736 $required_fields['card_city'] = [
737 'error_id' => 'invalid_city',
738 'error_message' => __( 'Please enter your billing city.', 'give' ),
739 ];
740 $required_fields['billing_country'] = [
741 'error_id' => 'invalid_country',
742 'error_message' => __( 'Please select your billing country.', 'give' ),
743 ];
744
745 $required_fields['card_state'] = [
746 'error_id' => 'invalid_state',
747 'error_message' => __( 'Please enter billing state / province / County.', 'give' ),
748 ];
749
750 $country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
751
752 // Check if billing country already exists.
753 if ( $country ) {
754
755 // Check if states is empty or not.
756 if ( array_key_exists( $country, give_states_not_required_country_list() ) ) {
757 // If states is empty remove the required fields of state in billing cart.
758 unset( $required_fields['card_state'] );
759 }
760
761 // Check if city is empty or not.
762 if ( array_key_exists( $country, give_city_not_required_country_list() ) ) {
763 // If states is empty remove the required fields of city in billing cart.
764 unset( $required_fields['card_city'] );
765 }
766
767 // Check if country is without post codes.
768 if ( array_key_exists( $country, give_get_country_list_without_postcodes() ) ) {
769 // If country is on the list, zip code is not required.
770 unset( $required_fields['card_zip'] );
771 }
772 }
773 } // End if().
774
775 if ( give_is_company_field_enabled( $form_id ) ) {
776 $form_option = give_get_meta( $form_id, '_give_company_field', true );
777 $global_setting = give_get_option( 'company_field' );
778
779 $is_company_field_required = false;
780
781 if ( ! empty( $form_option ) && give_is_setting_enabled( $form_option, [ 'required' ] ) ) {
782 $is_company_field_required = true;
783
784 } elseif ( 'global' === $form_option && give_is_setting_enabled( $global_setting, [ 'required' ] ) ) {
785 $is_company_field_required = true;
786
787 } elseif ( empty( $form_option ) && give_is_setting_enabled( $global_setting, [ 'required' ] ) ) {
788 $is_company_field_required = true;
789
790 }
791
792 if ( $is_company_field_required ) {
793 $required_fields['give_company_name'] = [
794 'error_id' => 'invalid_company',
795 'error_message' => __( 'Please enter Company Name.', 'give' ),
796 ];
797 }
798 }
799
800 if ( give_is_last_name_required( $form_id ) ) {
801 $required_fields['give_last'] = [
802 'error_id' => 'invalid_last_name',
803 'error_message' => __( 'Please enter your last name.', 'give' ),
804 ];
805 }
806
807 /**
808 * Filters the donation form required field.
809 *
810 * @since 1.7
811 */
812 $required_fields = apply_filters( 'give_donation_form_required_fields', $required_fields, $form_id );
813
814 return $required_fields;
815
816 }
817
818 /**
819 * Check if the Billing Address is required
820 *
821 * @since 1.0.1
822 *
823 * @param string $payment_mode Payment Mode.
824 *
825 * @return bool
826 */
827 function give_require_billing_address( $payment_mode ) {
828
829 $return = false;
830 $billing_country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
831
832 if ( $billing_country || did_action( "give_{$payment_mode}_cc_form" ) || did_action( 'give_cc_form' ) ) {
833 $return = true;
834 }
835
836 // Let payment gateways and other extensions determine if address fields should be required.
837 return apply_filters( 'give_require_billing_address', $return );
838
839 }
840
841 /**
842 * Donation Form Validate Logged In User.
843 *
844 * @access private
845 * @since 1.0
846 *
847 * @return array
848 */
849 function give_donation_form_validate_logged_in_user() {
850
851 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
852 $user_id = get_current_user_id();
853 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
854
855 // Start empty array to collect valid user data.
856 $valid_user_data = [
857
858 // Assume there will be errors.
859 'user_id' => - 1,
860 ];
861
862 // Proceed only, if valid $user_id found.
863 if ( $user_id > 0 ) {
864
865 // Get the logged in user data.
866 $user_data = get_userdata( $user_id );
867
868 // Validate Required Form Fields.
869 give_validate_required_form_fields( $form_id );
870
871 // Verify data.
872 if ( is_object( $user_data ) && $user_data->ID > 0 ) {
873 // Collected logged in user data.
874 $valid_user_data = [
875 'user_id' => $user_id,
876 'user_email' => ! empty( $post_data['give_email'] )
877 ? sanitize_email( $post_data['give_email'] )
878 : $user_data->user_email,
879 'user_first' => ! empty( $post_data['give_first'] )
880 ? $post_data['give_first']
881 : $user_data->first_name,
882 'user_last' => ! empty( $post_data['give_last'] )
883 ? $post_data['give_last']
884 : $user_data->last_name,
885 ];
886
887 // Validate essential form fields.
888 give_donation_form_validate_name_fields( $post_data );
889
890 give_check_logged_in_user_for_existing_email( $valid_user_data );
891
892 if ( ! is_email( $valid_user_data['user_email'] ) ) {
893 give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
894 }
895 } else {
896
897 // Set invalid user information error.
898 give_set_error( 'invalid_user', esc_html__( 'The user information is invalid.', 'give' ) );
899 }
900 }
901
902 // Return user data.
903 return $valid_user_data;
904 }
905
906 /**
907 * Donate Form Validate New User
908 *
909 * @access private
910 * @since 1.0
911 *
912 * @return array
913 */
914 function give_donation_form_validate_new_user() {
915 // Default user data.
916 $auto_generated_password = wp_generate_password();
917 $default_user_data = [
918 'give-form-id' => '',
919 'user_id' => - 1, // Assume there will be errors.
920 'user_first' => '',
921 'user_last' => '',
922 'give_user_login' => false,
923 'give_email' => false,
924 'give_user_pass' => $auto_generated_password,
925 'give_user_pass_confirm' => $auto_generated_password,
926 ];
927
928 // Get data.
929 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
930 $user_data = wp_parse_args( $post_data, $default_user_data );
931
932 $form_id = absint( $user_data['give-form-id'] );
933 $nonce = ! empty( $post_data['give-form-user-register-hash'] ) ? $post_data['give-form-user-register-hash'] : '';
934
935 // Validate user creation nonce.
936 if ( ! wp_verify_nonce( $nonce, "give_form_create_user_nonce_{$form_id}" ) ) {
937 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' ) );
938 }
939
940 $registering_new_user = false;
941
942 give_donation_form_validate_name_fields( $user_data );
943
944 // Start an empty array to collect valid user data.
945 $valid_user_data = [
946
947 // Assume there will be errors.
948 'user_id' => - 1,
949
950 // Get first name.
951 'user_first' => $user_data['give_first'],
952
953 // Get last name.
954 'user_last' => $user_data['give_last'],
955
956 // Get Password.
957 'user_pass' => $user_data['give_user_pass'],
958 ];
959
960 // Validate Required Form Fields.
961 give_validate_required_form_fields( $form_id );
962
963 // Set Email as Username.
964 $valid_user_data['user_login'] = $user_data['give_email'];
965
966 // Check if we have an email to verify.
967 if ( give_validate_user_email( $user_data['give_email'], $registering_new_user ) ) {
968 $valid_user_data['user_email'] = $user_data['give_email'];
969 }
970
971 return $valid_user_data;
972 }
973
974 /**
975 * Donation Form Validate User Login
976 *
977 * @access private
978 * @since 1.0
979 *
980 * @return array
981 */
982 function give_donation_form_validate_user_login() {
983
984 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
985
986 // Start an array to collect valid user data.
987 $valid_user_data = [
988
989 // Assume there will be errors.
990 'user_id' => - 1,
991 ];
992
993 // Bailout, if Username is empty.
994 if ( empty( $post_data['give_user_login'] ) ) {
995 give_set_error( 'must_log_in', __( 'Please enter your username or email to log in.', 'give' ) );
996
997 return $valid_user_data;
998 }
999
1000 $give_user_login = strip_tags( $post_data['give_user_login'] );
1001 if ( is_email( $give_user_login ) ) {
1002 // Get the user data by email.
1003 $user_data = get_user_by( 'email', $give_user_login );
1004 } else {
1005 // Get the user data by login.
1006 $user_data = get_user_by( 'login', $give_user_login );
1007 }
1008
1009 // Check if user exists.
1010 if ( $user_data ) {
1011
1012 // Get password.
1013 $user_pass = ! empty( $post_data['give_user_pass'] ) ? $post_data['give_user_pass'] : false;
1014
1015 // Check user_pass.
1016 if ( $user_pass ) {
1017
1018 // Check if password is valid.
1019 if ( ! wp_check_password( $user_pass, $user_data->user_pass, $user_data->ID ) ) {
1020
1021 $current_page_url = site_url() . '/' . get_page_uri();
1022
1023 // Incorrect password.
1024 give_set_error(
1025 'password_incorrect',
1026 sprintf(
1027 '%1$s <a href="%2$s">%3$s</a>',
1028 __( 'The password you entered is incorrect.', 'give' ),
1029 wp_lostpassword_url( $current_page_url ),
1030 __( 'Reset Password', 'give' )
1031 )
1032 );
1033
1034 } else {
1035
1036 // Repopulate the valid user data array.
1037 $valid_user_data = [
1038 'user_id' => $user_data->ID,
1039 'user_login' => $user_data->user_login,
1040 'user_email' => $user_data->user_email,
1041 'user_first' => $user_data->first_name,
1042 'user_last' => $user_data->last_name,
1043 'user_pass' => $user_pass,
1044 ];
1045 }
1046 } else {
1047 // Empty password.
1048 give_set_error( 'password_empty', __( 'Enter a password.', 'give' ) );
1049 }
1050 } else {
1051 // No username.
1052 give_set_error( 'username_incorrect', __( 'The username you entered does not exist.', 'give' ) );
1053 } // End if().
1054
1055 return $valid_user_data;
1056 }
1057
1058 /**
1059 * Donation Form Validate Guest User
1060 *
1061 * @access private
1062 * @since 1.0
1063 *
1064 * @return array
1065 */
1066 function give_donation_form_validate_guest_user() {
1067
1068 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1069 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
1070
1071 // Start an array to collect valid user data.
1072 $valid_user_data = [
1073 // Set a default id for guests.
1074 'user_id' => 0,
1075 ];
1076
1077 // Validate name fields.
1078 give_donation_form_validate_name_fields( $post_data );
1079
1080 // Validate Required Form Fields.
1081 give_validate_required_form_fields( $form_id );
1082
1083 // Get the guest email.
1084 $guest_email = ! empty( $post_data['give_email'] ) ? $post_data['give_email'] : false;
1085
1086 // Check email.
1087 if ( $guest_email && strlen( $guest_email ) > 0 ) {
1088
1089 // Validate email.
1090 if ( ! is_email( $guest_email ) ) {
1091
1092 // Invalid email.
1093 give_set_error( 'email_invalid', __( 'Invalid email.', 'give' ) );
1094
1095 } else {
1096
1097 // All is good to go.
1098 $valid_user_data['user_email'] = $guest_email;
1099
1100 // Get user_id from donor if exist.
1101 $donor = new Give_Donor( $guest_email );
1102
1103 if ( $donor->id ) {
1104 $donor_email_index = array_search(
1105 strtolower( $guest_email ),
1106 array_map( 'strtolower', $donor->emails ),
1107 true
1108 );
1109
1110 $valid_user_data['user_id'] = $donor->user_id;
1111
1112 // Set email to original format.
1113 // @see https://github.com/impress-org/give/issues/4025
1114 $valid_user_data['user_email'] = $donor->emails[ $donor_email_index ];
1115 }
1116 }
1117 } else {
1118 // No email.
1119 give_set_error( 'email_empty', __( 'Enter an email.', 'give' ) );
1120 }
1121
1122 return $valid_user_data;
1123 }
1124
1125 /**
1126 * Register And Login New User
1127 *
1128 * @param array $user_data User Data.
1129 *
1130 * @access private
1131 * @since 1.0
1132 *
1133 * @return integer
1134 */
1135 function give_register_and_login_new_user( $user_data = [] ) {
1136 // Verify the array.
1137 if ( empty( $user_data ) ) {
1138 return - 1;
1139 }
1140
1141 if ( give_get_errors() ) {
1142 return - 1;
1143 }
1144
1145 $user_args = apply_filters(
1146 'give_insert_user_args',
1147 [
1148 'user_login' => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
1149 'user_pass' => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
1150 'user_email' => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
1151 'first_name' => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
1152 'last_name' => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
1153 'user_registered' => date( 'Y-m-d H:i:s' ),
1154 'role' => give_get_option( 'donor_default_user_role', 'give_donor' ),
1155 ],
1156 $user_data
1157 );
1158
1159 // Insert new user.
1160 $user_id = wp_insert_user( $user_args );
1161
1162 // Validate inserted user.
1163 if ( is_wp_error( $user_id ) ) {
1164 return - 1;
1165 }
1166
1167 // Allow themes and plugins to filter the user data.
1168 $user_data = apply_filters( 'give_insert_user_data', $user_data, $user_args );
1169
1170 /**
1171 * Fires after inserting user.
1172 *
1173 * @since 1.0
1174 *
1175 * @param int $user_id User id.
1176 * @param array $user_data Array containing user data.
1177 */
1178 do_action( 'give_insert_user', $user_id, $user_data );
1179
1180 /**
1181 * Filter allow user to alter if user when to login or not when user is register for the first time.
1182 *
1183 * @since 1.8.13
1184 *
1185 * return bool True if login with registration and False if only want to register.
1186 */
1187 if ( true === (bool) apply_filters( 'give_log_user_in_on_register', true ) ) {
1188 // Login new user.
1189 give_log_user_in( $user_id, $user_data['user_login'], $user_data['user_pass'] );
1190 }
1191
1192 // Return user id.
1193 return $user_id;
1194 }
1195
1196 /**
1197 * Get Donation Form User
1198 *
1199 * @since 1.0
1200 * @since 2.17.1 Do not run validation check for ajax request expect donation validation ajax request.
1201 *
1202 * @param array $valid_data Valid Data.
1203 *
1204 * @access private
1205 * @return array|bool
1206 */
1207 function give_get_donation_form_user( $valid_data = [] ) {
1208 // Initialize user.
1209 $user = false;
1210 $post_data = give_clean($_POST); // WPCS: input var ok, sanitization ok, CSRF ok.
1211 $is_validating_donation_form_on_ajax = ! empty($_POST['give_ajax']) ? $post_data['give_ajax'] : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
1212
1213 if ( $is_validating_donation_form_on_ajax ) {
1214 // Do not create or login the user during the ajax submission (check for errors only).
1215 return true;
1216 } elseif ( is_user_logged_in() ) {
1217 // Set the valid user as the logged in collected data.
1218 $user = $valid_data['logged_in_user'];
1219 } elseif ( true === $valid_data['need_new_user'] || true === $valid_data['need_user_login'] ) {
1220 // New user registration.
1221 if ( true === $valid_data['need_new_user'] ) {
1222 // Set user.
1223 $user = $valid_data['new_user_data'];
1224
1225 // Register and login new user.
1226 $user['user_id'] = give_register_and_login_new_user($user);
1227 } elseif ( true === $valid_data['need_user_login'] ) {
1228 /**
1229 * The login form is now processed in the give_process_donation_login() function.
1230 * This is still here for backwards compatibility.
1231 * This also allows the old login process to still work if a user removes the checkout login submit button.
1232 *
1233 * 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.
1234 */
1235 $user = $valid_data['login_user_data'];
1236
1237 // Login user.
1238 give_log_user_in( $user['user_id'], $user['user_login'], $user['user_pass'] );
1239 }
1240 } // End if().
1241
1242 // Check guest checkout.
1243 if ( false === $user && false === give_logged_in_only( $post_data['give-form-id'] ) ) {
1244
1245 // Set user.
1246 $user = $valid_data['guest_user_data'];
1247 }
1248
1249 // Verify we have an user.
1250 if ( false === $user || empty( $user ) ) {
1251 return false;
1252 }
1253
1254 // Get user first name.
1255 if ( ! isset( $user['user_first'] ) || strlen( trim( $user['user_first'] ) ) < 1 ) {
1256 $user['user_first'] = isset( $post_data['give_first'] ) ? strip_tags( trim( $post_data['give_first'] ) ) : '';
1257 }
1258
1259 // Get user last name.
1260 if ( ! isset( $user['user_last'] ) || strlen( trim( $user['user_last'] ) ) < 1 ) {
1261 $user['user_last'] = isset( $post_data['give_last'] ) ? strip_tags( trim( $post_data['give_last'] ) ) : '';
1262 }
1263
1264 // Add Title Prefix to user information.
1265 if ( empty( $user['user_title'] ) || strlen( trim( $user['user_title'] ) ) < 1 ) {
1266 $user['user_title'] = ! empty( $post_data['give_title'] ) ? strip_tags( trim( $post_data['give_title'] ) ) : '';
1267 }
1268
1269 // Get the user's billing address details.
1270 $user['address'] = [];
1271 $user['address']['line1'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : false;
1272 $user['address']['line2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : false;
1273 $user['address']['city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : false;
1274 $user['address']['state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : false;
1275 $user['address']['zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : false;
1276 $user['address']['country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : false;
1277
1278 if ( empty( $user['address']['country'] ) ) {
1279 $user['address'] = false;
1280 } // End if().
1281
1282 // Return valid user.
1283 return $user;
1284 }
1285
1286 /**
1287 * Validates the credit card info.
1288 *
1289 * @access private
1290 * @since 1.0
1291 *
1292 * @return array
1293 */
1294 function give_donation_form_validate_cc() {
1295
1296 $card_data = give_get_donation_cc_info();
1297
1298 // Validate the card zip.
1299 if ( ! empty( $card_data['card_zip'] ) ) {
1300 if ( ! give_donation_form_validate_cc_zip( $card_data['card_zip'], $card_data['card_country'] ) ) {
1301 give_set_error( 'invalid_cc_zip', __( 'The zip / postal code you entered for your billing address is invalid.', 'give' ) );
1302 }
1303 }
1304
1305 // Ensure no spaces.
1306 if ( ! empty( $card_data['card_number'] ) ) {
1307 $card_data['card_number'] = str_replace( '+', '', $card_data['card_number'] ); // no "+" signs.
1308 $card_data['card_number'] = str_replace( ' ', '', $card_data['card_number'] ); // No spaces.
1309 }
1310
1311 // This should validate card numbers at some point too.
1312 return $card_data;
1313 }
1314
1315 /**
1316 * Get credit card info.
1317 *
1318 * @access private
1319 * @since 1.0
1320 *
1321 * @return array
1322 */
1323 function give_get_donation_cc_info() {
1324
1325 // Sanitize the values submitted with donation form.
1326 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1327
1328 $cc_info = [];
1329 $cc_info['card_name'] = ! empty( $post_data['card_name'] ) ? $post_data['card_name'] : '';
1330 $cc_info['card_number'] = ! empty( $post_data['card_number'] ) ? $post_data['card_number'] : '';
1331 $cc_info['card_cvc'] = ! empty( $post_data['card_cvc'] ) ? $post_data['card_cvc'] : '';
1332 $cc_info['card_exp_month'] = ! empty( $post_data['card_exp_month'] ) ? $post_data['card_exp_month'] : '';
1333 $cc_info['card_exp_year'] = ! empty( $post_data['card_exp_year'] ) ? $post_data['card_exp_year'] : '';
1334 $cc_info['card_address'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : '';
1335 $cc_info['card_address_2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : '';
1336 $cc_info['card_city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : '';
1337 $cc_info['card_state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : '';
1338 $cc_info['card_country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : '';
1339 $cc_info['card_zip'] = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : '';
1340
1341 // Return cc info.
1342 return $cc_info;
1343 }
1344
1345 /**
1346 * Validate zip code based on country code
1347 *
1348 * @since 1.0
1349 *
1350 * @param int $zip ZIP Code.
1351 * @param string $country_code Country Code.
1352 *
1353 * @return bool|mixed
1354 */
1355 function give_donation_form_validate_cc_zip( $zip = 0, $country_code = '' ) {
1356 $ret = false;
1357
1358 if ( empty( $zip ) || empty( $country_code ) ) {
1359 return $ret;
1360 }
1361
1362 $country_code = strtoupper( $country_code );
1363
1364 $zip_regex = [
1365 'AD' => 'AD\d{3}',
1366 'AM' => '(37)?\d{4}',
1367 'AR' => '^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$',
1368 'AS' => '96799',
1369 'AT' => '\d{4}',
1370 '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})$',
1371 'AX' => '22\d{3}',
1372 'AZ' => '\d{4}',
1373 'BA' => '\d{5}',
1374 'BB' => '(BB\d{5})?',
1375 'BD' => '\d{4}',
1376 'BE' => '^[1-9]{1}[0-9]{3}$',
1377 'BG' => '\d{4}',
1378 'BH' => '((1[0-2]|[2-9])\d{2})?',
1379 'BM' => '[A-Z]{2}[ ]?[A-Z0-9]{2}',
1380 'BN' => '[A-Z]{2}[ ]?\d{4}',
1381 'BR' => '\d{5}[\-]?\d{3}',
1382 'BY' => '\d{6}',
1383 'CA' => '^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$',
1384 'CC' => '6799',
1385 'CH' => '^[1-9][0-9][0-9][0-9]$',
1386 'CK' => '\d{4}',
1387 'CL' => '\d{7}',
1388 'CN' => '\d{6}',
1389 'CR' => '\d{4,5}|\d{3}-\d{4}',
1390 'CS' => '\d{5}',
1391 'CV' => '\d{4}',
1392 'CX' => '6798',
1393 'CY' => '\d{4}',
1394 'CZ' => '\d{3}[ ]?\d{2}',
1395 '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',
1396 'DK' => '^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$',
1397 'DO' => '\d{5}',
1398 'DZ' => '\d{5}',
1399 'EC' => '([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?',
1400 'EE' => '\d{5}',
1401 'EG' => '\d{5}',
1402 'ES' => '^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$',
1403 'ET' => '\d{4}',
1404 'FI' => '\d{5}',
1405 'FK' => 'FIQQ 1ZZ',
1406 'FM' => '(9694[1-4])([ \-]\d{4})?',
1407 'FO' => '\d{3}',
1408 'FR' => '^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$',
1409 'GE' => '\d{4}',
1410 'GF' => '9[78]3\d{2}',
1411 'GL' => '39\d{2}',
1412 'GN' => '\d{3}',
1413 'GP' => '9[78][01]\d{2}',
1414 'GR' => '\d{3}[ ]?\d{2}',
1415 'GS' => 'SIQQ 1ZZ',
1416 'GT' => '\d{5}',
1417 'GU' => '969[123]\d([ \-]\d{4})?',
1418 'GW' => '\d{4}',
1419 'HM' => '\d{4}',
1420 'HN' => '(?:\d{5})?',
1421 'HR' => '\d{5}',
1422 'HT' => '\d{4}',
1423 'HU' => '\d{4}',
1424 'ID' => '\d{5}',
1425 'IE' => '((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?',
1426 'IL' => '\d{5}',
1427 'IN' => '^[1-9][0-9][0-9][0-9][0-9][0-9]$', // India.
1428 'IO' => 'BBND 1ZZ',
1429 'IQ' => '\d{5}',
1430 'IS' => '\d{3}',
1431 'IT' => '^(V-|I-)?[0-9]{5}$',
1432 'JO' => '\d{5}',
1433 'JP' => '\d{3}-\d{4}',
1434 'KE' => '\d{5}',
1435 'KG' => '\d{6}',
1436 'KH' => '\d{5}',
1437 'KR' => '\d{5}',
1438 'KW' => '\d{5}',
1439 'KZ' => '\d{6}',
1440 'LA' => '\d{5}',
1441 'LB' => '(\d{4}([ ]?\d{4})?)?',
1442 'LI' => '(948[5-9])|(949[0-7])',
1443 'LK' => '\d{5}',
1444 'LR' => '\d{4}',
1445 'LS' => '\d{3}',
1446 'LT' => '\d{5}',
1447 'LU' => '\d{4}',
1448 'LV' => '\d{4}',
1449 'MA' => '\d{5}',
1450 'MC' => '980\d{2}',
1451 'MD' => '\d{4}',
1452 'ME' => '8\d{4}',
1453 'MG' => '\d{3}',
1454 'MH' => '969[67]\d([ \-]\d{4})?',
1455 'MK' => '\d{4}',
1456 'MN' => '\d{6}',
1457 'MP' => '9695[012]([ \-]\d{4})?',
1458 'MQ' => '9[78]2\d{2}',
1459 'MT' => '[A-Z]{3}[ ]?\d{2,4}',
1460 'MU' => '(\d{3}[A-Z]{2}\d{3})?',
1461 'MV' => '\d{5}',
1462 'MX' => '\d{5}',
1463 'MY' => '\d{5}',
1464 'NC' => '988\d{2}',
1465 'NE' => '\d{4}',
1466 'NF' => '2899',
1467 'NG' => '(\d{6})?',
1468 'NI' => '((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?',
1469 'NL' => '^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$',
1470 'NO' => '\d{4}',
1471 'NP' => '\d{5}',
1472 'NZ' => '\d{4}',
1473 'OM' => '(PC )?\d{3}',
1474 'PF' => '987\d{2}',
1475 'PG' => '\d{3}',
1476 'PH' => '\d{4}',
1477 'PK' => '\d{5}',
1478 'PL' => '\d{2}-\d{3}',
1479 'PM' => '9[78]5\d{2}',
1480 'PN' => 'PCRN 1ZZ',
1481 'PR' => '00[679]\d{2}([ \-]\d{4})?',
1482 'PT' => '\d{4}([\-]\d{3})?',
1483 'PW' => '96940',
1484 'PY' => '\d{4}',
1485 'RE' => '9[78]4\d{2}',
1486 'RO' => '\d{6}',
1487 'RS' => '\d{5}',
1488 'RU' => '\d{6}',
1489 'SA' => '\d{5}',
1490 'SE' => '^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$',
1491 'SG' => '\d{6}',
1492 'SH' => '(ASCN|STHL) 1ZZ',
1493 'SI' => '\d{4}',
1494 'SJ' => '\d{4}',
1495 'SK' => '\d{3}[ ]?\d{2}',
1496 'SM' => '4789\d',
1497 'SN' => '\d{5}',
1498 'SO' => '\d{5}',
1499 'SZ' => '[HLMS]\d{3}',
1500 'TC' => 'TKCA 1ZZ',
1501 'TH' => '\d{5}',
1502 'TJ' => '\d{6}',
1503 'TM' => '\d{6}',
1504 'TN' => '\d{4}',
1505 'TR' => '\d{5}',
1506 'TW' => '\d{3}(\d{2})?',
1507 'UA' => '\d{5}',
1508 'UK' => '^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$',
1509 'US' => '^\d{5}([\-]?\d{4})?$',
1510 'UY' => '\d{5}',
1511 'UZ' => '\d{6}',
1512 'VA' => '00120',
1513 'VE' => '\d{4}',
1514 'VI' => '008(([0-4]\d)|(5[01]))([ \-]\d{4})?',
1515 'WF' => '986\d{2}',
1516 'YT' => '976\d{2}',
1517 'YU' => '\d{5}',
1518 'ZA' => '\d{4}',
1519 'ZM' => '\d{5}',
1520 ];
1521
1522 if ( ! isset( $zip_regex[ $country_code ] ) || preg_match( '/' . $zip_regex[ $country_code ] . '/i', $zip ) ) {
1523 $ret = true;
1524 }
1525
1526 return apply_filters( 'give_is_zip_valid', $ret, $zip, $country_code );
1527 }
1528
1529 /**
1530 * Validate donation amount and auto set correct donation level id on basis of amount.
1531 *
1532 * 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.
1533 *
1534 * @param array $valid_data List of Valid Data.
1535 *
1536 * @return bool
1537 */
1538 function give_validate_donation_amount( $valid_data ) {
1539
1540 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1541
1542 /* @var Give_Donate_Form $form */
1543 $form = new Give_Donate_Form( $post_data['give-form-id'] );
1544
1545 // Get the form currency.
1546 $form_currency = give_get_currency( $post_data['give-form-id'] );
1547
1548 $donation_level_matched = false;
1549
1550 if ( $form->is_set_type_donation_form() ) {
1551
1552 // Sanitize donation amount.
1553 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => $form_currency ] );
1554
1555 // Backward compatibility.
1556 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1557 $post_data['give-price-id'] = 'custom';
1558 }
1559
1560 $donation_level_matched = true;
1561
1562 } elseif ( $form->is_multi_type_donation_form() ) {
1563
1564 $variable_prices = $form->get_prices();
1565
1566 // Bailout.
1567 if ( ! $variable_prices ) {
1568 return false;
1569 }
1570
1571 // Sanitize donation amount.
1572 $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => $form_currency ] );
1573 $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 ] );
1574 $new_price_id = '';
1575
1576 if ( $post_data['give-amount'] === $variable_price_option_amount ) {
1577 return true;
1578 }
1579
1580 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1581 $new_price_id = 'custom';
1582 } else {
1583
1584 // Find correct donation level from all donation levels.
1585 foreach ( $variable_prices as $variable_price ) {
1586
1587 // Sanitize level amount.
1588 $variable_price['_give_amount'] = give_maybe_sanitize_amount( $variable_price['_give_amount'] );
1589
1590 // Set first match donation level ID.
1591 if ( $post_data['give-amount'] === $variable_price['_give_amount'] ) {
1592 $new_price_id = $variable_price['_give_id']['level_id'];
1593 break;
1594 }
1595 }
1596 }
1597
1598 // If donation amount is not find in donation levels then check if form has custom donation feature enable or not.
1599 // If yes then set price id to custom if amount is greater then custom minimum amount (if any).
1600 if ( $post_data['give-price-id'] === $new_price_id ) {
1601 $donation_level_matched = true;
1602 }
1603 } // End if().
1604
1605 if ( ! $donation_level_matched ) {
1606 give_set_error(
1607 'invalid_donation_amount',
1608 sprintf(
1609 /* translators: %s: invalid donation amount */
1610 __( 'Donation amount %s is invalid.', 'give' ),
1611 give_currency_filter(
1612 give_format_amount( $post_data['give-amount'], [ 'sanitize' => false ] )
1613 )
1614 )
1615 );
1616 }
1617 }
1618
1619 add_action( 'give_checkout_error_checks', 'give_validate_donation_amount', 10, 1 );
1620
1621 /**
1622 * Validate Required Form Fields.
1623 *
1624 * @param int $form_id Form ID.
1625 *
1626 * @since 2.0
1627 */
1628 function give_validate_required_form_fields( $form_id ) {
1629 // Sanitize values submitted with donation form.
1630 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1631 $requiredFormFields = give_get_required_fields( $form_id );
1632
1633 // Loop through required fields and show error messages.
1634 foreach ( $requiredFormFields as $field_name => $value ) {
1635 if ( empty( $post_data[ $field_name ] ) ) {
1636 give_set_error( $value['error_id'], $value['error_message'] );
1637 }
1638 }
1639 }
1640
1641 /**
1642 * Validates and checks if name fields are valid or not.
1643 *
1644 * @param array $post_data List of post data.
1645 *
1646 * @since 2.1
1647 *
1648 * @return void
1649 */
1650 function give_donation_form_validate_name_fields( $post_data ) {
1651
1652 $is_alpha_first_name = ( ! is_email( $post_data['give_first'] ) && ! preg_match( '~[0-9]~', $post_data['give_first'] ) );
1653 $is_alpha_last_name = ( ! is_email( $post_data['give_last'] ) && ! preg_match( '~[0-9]~', $post_data['give_last'] ) );
1654
1655 if ( ! $is_alpha_first_name || ( ! empty( $post_data['give_last'] ) && ! $is_alpha_last_name ) ) {
1656 give_set_error( 'invalid_name', esc_html__( 'The First Name and Last Name fields cannot contain an email address or numbers.', 'give' ) );
1657 }
1658 }
1659