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