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