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