PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.16.9
GiveWP – Donation Plugin and Fundraising Platform v4.16.9
4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 All 255 releases
← All changes | includes/process-donation.php +457 -223 2.3.24.16.9 View file →
@@ -8,8 +8,12 @@
8 8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 9 * @since 1.0
10 10 */
11 11
12 +use Give\Helpers\Form\Utils as FormUtils;
13 +use Give\Helpers\Frontend\Shortcode as ShortcodeUtils;
14 +use Give\Helpers\Utils;
15 +
12 16 // Exit if accessed directly.
13 17 if ( ! defined( 'ABSPATH' ) ) {
14 18 exit;
15 19 }
@@ -19,8 +23,11 @@
19 23 *
20 24 * Handles the donation form process.
21 25 *
22 26 * @access private
27 + * @since 4.16.7.2 Reject serialized data in name fields before storing donation data.
28 + * @since 4.16.6 Bail early when the form ID is not a give_forms post or is a Visual Form Builder (v3) form.
29 + * @since 3.16.1 Use give_maybe_safe_unserialize() on $user_info data
23 30 * @since 1.0
24 31 *
25 32 * @throws ReflectionException Exception Handling.
26 33 *
@@ -28,9 +35,9 @@
28 35 */
29 36 function give_process_donation_form() {
30 37
31 38 // Sanitize Posted Data.
32 - $post_data = give_clean( $_POST ); // WPCS: input var ok, CSRF ok.
39 + $post_data = give_clean( $_POST ); // WPCS: input var ok, CSRF ok.
33 40
34 41 // Check whether the form submitted via AJAX or not.
35 42 $is_ajax = isset( $post_data['give_ajax'] );
36 43
@@ -48,8 +55,48 @@
48 55 give_send_back_to_checkout();
49 56 }
50 57 }
51 58
59 + $form_id = isset( $post_data['give-form-id'] ) ? absint( $post_data['give-form-id'] ) : 0;
60 +
61 + if ( ! ShortcodeUtils::isValidForm( $form_id ) ) {
62 + give_set_error(
63 + 'give_invalid_donation_form',
64 + __( 'The donation form ID is invalid. Please reload the page and try again.', 'give' )
65 + );
66 +
67 + if ( $is_ajax ) {
68 + /** This action is documented in this file (see give_ajax_donation_errors above). */
69 + do_action( 'give_ajax_donation_errors' );
70 + give_die();
71 + return;
72 + }
73 +
74 + give_send_back_to_checkout();
75 +
76 + return false;
77 + }
78 +
79 + // Visual Form Builder (v3) forms are processed through the givewp-donate route,
80 + // so bail out when the legacy donation processor receives one.
81 + if ( FormUtils::isV3Form( $form_id ) ) {
82 + give_set_error(
83 + 'give_unsupported_form_version',
84 + __( 'This donation form cannot be processed through this endpoint. Please reload the page and try again.', 'give' )
85 + );
86 +
87 + if ( $is_ajax ) {
88 + /** This action is documented in this file (see give_ajax_donation_errors above). */
89 + do_action( 'give_ajax_donation_errors' );
90 + give_die();
91 + return;
92 + }
93 +
94 + give_send_back_to_checkout();
95 +
96 + return false;
97 + }
98 +
52 99 /**
53 100 * Fires before processing the donation form.
54 101 *
55 102 * @since 1.0
@@ -79,9 +126,9 @@
79 126
80 127 // Validate the user.
81 128 $user = give_get_donation_form_user( $valid_data );
82 129
83 - if ( false === $valid_data || give_get_errors() || ! $user ) {
130 + if ( false === $valid_data || ! $user || give_get_errors() ) {
84 131 if ( $is_ajax ) {
85 132 /**
86 133 * Fires when AJAX sends back errors from the donation form.
87 134 *
@@ -107,9 +154,9 @@
107 154 */
108 155 do_action( 'give_process_donation_after_validation' );
109 156
110 157 // Setup user information.
111 - $user_info = array(
158 + $user_info = [
112 159 'id' => $user['user_id'],
113 160 'title' => $user['user_title'],
114 161 'email' => $user['user_email'],
115 162 'first_name' => $user['user_first'],
@@ -114,17 +161,30 @@
114 161 'email' => $user['user_email'],
115 162 'first_name' => $user['user_first'],
116 163 'last_name' => $user['user_last'],
117 164 'address' => $user['address'],
165 + ];
166 +
167 + // Reject serialized data in name fields.
168 + $serialized_keys = array_filter(
169 + $user_info,
170 + static function ( $value ) {
171 + return is_string( $value ) && \Give\Helpers\Utils::isSerialized( $value );
172 + }
118 173 );
119 174
175 + if ( ! empty( $serialized_keys ) ) {
176 + give_set_error( 'give_serialized_user_info', esc_html__( 'Name fields cannot contain serialized data.', 'give' ) );
177 + return;
178 + }
179 +
120 180 $auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
121 181
122 182 // Donation form ID.
123 183 $form_id = isset( $post_data['give-form-id'] ) ? absint( $post_data['give-form-id'] ) : 0;
124 184
125 - $price = isset( $post_data['give-amount'] ) ?
126 - (float) apply_filters( 'give_donation_total', give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => give_get_currency( $form_id ) ) ) ) :
185 + $price = isset( $post_data['give-amount'] ) ?
186 + (float) apply_filters( 'give_donation_total', give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => give_get_currency( $form_id ) ] ) ) :
127 187 '0.00';
128 188 $purchase_key = strtolower( md5( $user['user_email'] . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'give', true ) ) );
129 189
130 190 /**
@@ -150,18 +210,19 @@
150 210 $purchase_key
151 211 );
152 212
153 213 // Setup donation information.
154 - $donation_data = array(
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 - );
214 + $user_info = stripslashes_deep( $user_info );
215 + $donation_data = [
216 + 'price' => $price,
217 + 'purchase_key' => $purchase_key,
218 + 'user_email' => $user['user_email'],
219 + 'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
220 + 'user_info' => $user_info,
221 + 'post_data' => $post_data,
222 + 'gateway' => $valid_data['gateway'],
223 + 'card_info' => $valid_data['cc_info'],
224 + ];
164 225
165 226 // Add the user data for hooks.
166 227 $valid_data['user'] = $user;
167 228
@@ -201,10 +262,18 @@
201 262
202 263 // Used for showing data to non logged-in users after donation, and for other plugins needing donation data.
203 264 give_set_purchase_session( $session_data );
204 265
266 + /**
267 + * Prevent PHP notices from breaking receipt display.
268 + * This is specifically an issue with the Stripe SDK.
269 + *
270 + * @link https://github.com/impress-org/givewp/issues/5199
271 + */
272 + ob_start();
205 273 // Send info to the gateway for payment processing.
206 274 give_send_to_gateway( $donation_data['gateway'], $donation_data );
275 + ob_get_clean();
207 276 give_die();
208 277 }
209 278
210 279 add_action( 'give_purchase', 'give_process_donation_form' );
@@ -212,51 +281,65 @@
212 281 add_action( 'wp_ajax_nopriv_give_process_donation', 'give_process_donation_form' );
213 282
214 283 /**
215 284 * Verify that when a logged in user makes a donation that the email address used doesn't belong to a different customer.
285 + * Note: only for internal use
216 286 *
287 + * @see https://github.com/impress-org/give/issues/4025
288 + *
217 289 * @since 1.7
290 + * @since 2.4.2 This function runs independently instead of give_checkout_error_checks hook and also edit donor email.
218 291 *
219 292 * @param array $valid_data Validated data submitted for the donation.
220 293 *
221 294 * @return void
222 295 */
223 -function give_check_logged_in_user_for_existing_email( $valid_data ) {
296 +function give_check_logged_in_user_for_existing_email( &$valid_data ) {
224 297
225 - // Verify that the email address belongs to this customer.
298 + // Verify that the email address belongs to this donor.
226 299 if ( is_user_logged_in() ) {
227 300
228 - $submitted_email = $valid_data['logged_in_user']['user_email'];
229 - $donor = new Give_Donor( get_current_user_id(), true );
301 + $donor = new Give_Donor( get_current_user_id(), true );
230 302
303 + // Bailout: check if wp user is existing donor or not.
304 + if ( ! $donor->id ) {
305 + return;
306 + }
307 +
308 + $submitted_email = strtolower( $valid_data['user_email'] );
309 +
310 + $donor_emails = array_map( 'strtolower', $donor->emails );
311 + $email_index = array_search( $submitted_email, $donor_emails, true );
312 +
313 + // If donor matched with email then return set formatted email from database.
314 + if ( false !== $email_index ) {
315 + $valid_data['user_email'] = $donor->emails[ $email_index ];
316 +
317 + return;
318 + }
319 +
231 320 // If this email address is not registered with this customer, see if it belongs to any other customer.
232 - if (
233 - $submitted_email !== $donor->email
234 - && ( is_array( $donor->emails ) && ! in_array( $submitted_email, $donor->emails, true ) )
235 - ) {
236 - $found_donor = new Give_Donor( $submitted_email );
321 + $found_donor = new Give_Donor( $submitted_email );
237 322
238 - if ( $found_donor->id > 0 ) {
239 - give_set_error(
240 - 'give-customer-email-exists',
241 - sprintf(
242 - /* translators: 1. Donor Email, 2. Submitted Email */
243 - __( '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' ),
244 - $donor->email,
245 - $submitted_email
246 - )
247 - );
248 - }
323 + if ( $found_donor->id > 0 ) {
324 + give_set_error(
325 + 'give-customer-email-exists',
326 + sprintf(
327 + /* translators: 1. Donor Email, 2. Submitted Email */
328 + __( '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' ),
329 + $donor->email,
330 + $submitted_email
331 + )
332 + );
249 333 }
250 334 }
251 335 }
252 336
253 -add_action( 'give_checkout_error_checks', 'give_check_logged_in_user_for_existing_email', 10, 1 );
254 -
255 337 /**
256 338 * Process the checkout login form
257 339 *
258 340 * @access private
341 + * @since 4.16.7 Require a valid nonce before processing the login form.
259 342 * @since 1.0
260 343 *
261 344 * @return void
262 345 */
@@ -261,12 +344,23 @@
261 344 * @return void
262 345 */
263 346 function give_process_form_login() {
264 347
265 - $is_ajax = ! empty( $_POST['give_ajax'] ) ? give_clean( $_POST['give_ajax'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
266 - $referrer = wp_get_referer();
267 - $user_data = give_donation_form_validate_user_login();
348 + $is_ajax = ! empty( $_POST['give_ajax'] ) ? give_clean( $_POST['give_ajax'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
349 + $referrer = wp_get_referer();
268 350
351 + // Default to no user until the login form is validated.
352 + $user_data = [
353 + 'user_id' => - 1,
354 + ];
355 +
356 + // Require a valid nonce before processing the login form.
357 + if ( empty( $_POST['give_login_nonce'] ) || ! wp_verify_nonce( $_POST['give_login_nonce'], 'give-login-nonce' ) ) {
358 + give_set_error( 'invalid_nonce', __( 'Your session has expired. Please reload the page and try again.', 'give' ) );
359 + } else {
360 + $user_data = give_donation_form_validate_user_login();
361 + }
362 +
269 363 if ( give_get_errors() || $user_data['user_id'] < 1 ) {
270 364 if ( $is_ajax ) {
271 365 /**
272 366 * Fires when AJAX sends back errors from the donation form.
@@ -277,8 +371,9 @@
277 371 do_action( 'give_ajax_donation_errors' );
278 372 $message = ob_get_contents();
279 373 ob_end_clean();
280 374 wp_send_json_error( $message );
375 + return;
281 376 } else {
282 377 wp_safe_redirect( $referrer );
283 378 exit;
284 379 }
@@ -286,9 +381,9 @@
286 381
287 382 give_log_user_in( $user_data['user_id'], $user_data['user_login'], $user_data['user_pass'] );
288 383
289 384 if ( $is_ajax ) {
290 - $message = Give()->notices->print_frontend_notice(
385 + $message = Give_Notices::print_frontend_notice(
291 386 sprintf(
292 387 /* translators: %s: user first name */
293 388 esc_html__( 'Welcome %s! You have successfully logged into your account.', 'give' ),
294 389 ( ! empty( $user_data['user_first'] ) ) ? $user_data['user_first'] : $user_data['user_login']
@@ -309,8 +404,9 @@
309 404 /**
310 405 * Donation Form Validate Fields.
311 406 *
312 407 * @access private
408 + * @since 3.5.0 validate serialized fields
313 409 * @since 1.0
314 410 *
315 411 * @return bool|array
316 412 */
@@ -316,8 +412,9 @@
316 412 */
317 413 function give_donation_form_validate_fields() {
318 414
319 415 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
416 + give_donation_form_validate_name_fields($post_data);
320 417
321 418 // Validate Honeypot First.
322 419 if ( ! empty( $post_data['give-honeypot'] ) ) {
323 420 give_set_error( 'invalid_honeypot', esc_html__( 'Honeypot field detected. Go away bad bot!', 'give' ) );
@@ -322,30 +419,34 @@
322 419 if ( ! empty( $post_data['give-honeypot'] ) ) {
323 420 give_set_error( 'invalid_honeypot', esc_html__( 'Honeypot field detected. Go away bad bot!', 'give' ) );
324 421 }
325 422
423 + // Validate serialized fields.
424 + if (give_donation_form_has_serialized_fields($post_data)) {
425 + give_set_error('invalid_serialized_fields', esc_html__('Serialized fields detected. Go away!', 'give'));
426 + }
427 +
326 428 // Check spam detect.
327 429 if (
328 430 isset( $post_data['action'] )
329 - && give_is_setting_enabled( give_get_option( 'akismet_spam_protection' ) )
330 431 && give_is_spam_donation()
331 432 ) {
332 - give_set_error( 'spam_donation', __( 'This donation has been flagged as spam. Please try again.', 'give' ) );
433 + 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' ) );
333 434 }
334 435
335 436 // Start an array to collect valid data.
336 - $valid_data = array(
437 + $valid_data = [
337 438 'gateway' => give_donation_form_validate_gateway(), // Gateway fallback (amount is validated here).
338 439 'need_new_user' => false, // New user flag.
339 440 'need_user_login' => false, // Login user flag.
340 - 'logged_user_data' => array(), // Logged user collected data.
341 - 'new_user_data' => array(), // New user collected data.
342 - 'login_user_data' => array(), // Login user collected data.
343 - 'guest_user_data' => array(), // Guest user collected data.
441 + 'logged_user_data' => [], // Logged user collected data.
442 + 'new_user_data' => [], // New user collected data.
443 + 'login_user_data' => [], // Login user collected data.
444 + 'guest_user_data' => [], // Guest user collected data.
344 445 'cc_info' => give_donation_form_validate_cc(), // Credit card info.
345 - );
446 + ];
346 447
347 - $form_id = intval( $post_data['give-form-id'] );
448 + $form_id = (int) $post_data['give-form-id'];
348 449
349 450 // Validate agree to terms.
350 451 if ( give_is_terms_enabled( $form_id ) ) {
351 452 give_donation_form_validate_agree_to_terms();
@@ -355,11 +456,11 @@
355 456
356 457 // Collect logged in user data.
357 458 $valid_data['logged_in_user'] = give_donation_form_validate_logged_in_user();
358 459 } elseif (
359 - isset( $post_data['give-purchase-var'] ) &&
360 - 'needs-to-register' === $post_data['give-purchase-var'] &&
361 - ! empty( $post_data['give_create_account'] )
460 + isset( $post_data['give-purchase-var'] )
461 + && 'needs-to-register' === $post_data['give-purchase-var']
462 + && ! empty( $post_data['give_create_account'] )
362 463 ) {
363 464
364 465 // Set new user registration as required.
365 466 $valid_data['need_new_user'] = true;
@@ -366,10 +467,10 @@
366 467
367 468 // Validate new user data.
368 469 $valid_data['new_user_data'] = give_donation_form_validate_new_user();
369 470 } elseif (
370 - isset( $post_data['give-purchase-var'] ) &&
371 - 'needs-to-login' === $post_data['give-purchase-var']
471 + isset( $post_data['give-purchase-var'] )
472 + && 'needs-to-login' === $post_data['give-purchase-var']
372 473 ) {
373 474
374 475 // Set user login as required.
375 476 $valid_data['need_user_login'] = true;
@@ -386,8 +487,30 @@
386 487 return $valid_data;
387 488 }
388 489
389 490 /**
491 + * Detect serialized fields.
492 + *
493 + * @since 3.17.2 Use Utils::isSerialized() method which add supports to find hidden serialized data in the middle of a string
494 + * @since 3.16.5 Make sure only string parameters are used with the ltrim() method to prevent PHP 8+ fatal errors
495 + * @since 3.16.4 updated to check all values for serialized fields
496 + * @since 3.16.2 added additional check for stripslashes_deep
497 + * @since 3.14.2 add give-form-title, give_title
498 + * @since 3.5.0
499 + */
500 +function give_donation_form_has_serialized_fields(array $post_data): bool
501 +{
502 + foreach ($post_data as $value) {
503 +
504 + if (Utils::isSerialized($value)) {
505 + return true;
506 + }
507 + }
508 +
509 + return false;
510 +}
511 +
512 +/**
390 513 * Detect spam donation.
391 514 *
392 515 * @since 1.8.14
393 516 *
@@ -443,12 +566,13 @@
443 566 sprintf(
444 567 /* translators: %s: minimum donation amount */
445 568 __( 'This form has a minimum donation amount of %s.', 'give' ),
446 569 give_currency_filter(
447 - give_format_amount( give_get_form_minimum_price( $form_id ),
448 - array(
570 + give_format_amount(
571 + give_get_form_minimum_price( $form_id ),
572 + [
449 573 'sanitize' => false,
450 - )
574 + ]
451 575 )
452 576 )
453 577 )
454 578 );
@@ -459,12 +583,13 @@
459 583 sprintf(
460 584 /* translators: %s: Maximum donation amount */
461 585 __( 'This form has a maximum donation amount of %s.', 'give' ),
462 586 give_currency_filter(
463 - give_format_amount( give_get_form_maximum_price( $form_id ),
464 - array(
587 + give_format_amount(
588 + give_get_form_maximum_price( $form_id ),
589 + [
465 590 'sanitize' => false,
466 - )
591 + ]
467 592 )
468 593 )
469 594 )
470 595 );
@@ -489,9 +614,9 @@
489 614 function give_verify_minimum_price( $amount_range = 'minimum' ) {
490 615
491 616 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
492 617 $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'], array( 'currency' => give_get_currency( $form_id ) ) ) : 0;
618 + $amount = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => give_get_currency( $form_id ) ] ) : 0;
494 619 $price_id = isset( $post_data['give-price-id'] ) ? absint( $post_data['give-price-id'] ) : '';
495 620
496 621 $variable_prices = give_has_variable_prices( $form_id );
497 622 $price_ids = array_map( 'absint', give_get_variable_price_ids( $form_id ) );
@@ -507,12 +632,12 @@
507 632 }
508 633
509 634 if ( ! $verified_stat ) {
510 635 switch ( $amount_range ) {
511 - case 'minimum' :
636 + case 'minimum':
512 637 $verified_stat = ( give_get_form_minimum_price( $form_id ) > $amount ) ? false : true;
513 638 break;
514 - case 'maximum' :
639 + case 'maximum':
515 640 $verified_stat = ( give_get_form_maximum_price( $form_id ) < $amount ) ? false : true;
516 641 break;
517 642 }
518 643 }
@@ -560,54 +685,114 @@
560 685 * @return array
561 686 */
562 687 function give_get_required_fields( $form_id ) {
563 688
689 + $posted_data = give_clean( filter_input_array( INPUT_POST ) );
564 690 $payment_mode = give_get_chosen_gateway( $form_id );
565 691
566 - $required_fields = array(
567 - 'give_email' => array(
692 + $required_fields = [
693 + 'give_email' => [
568 694 'error_id' => 'invalid_email',
569 695 'error_message' => __( 'Please enter a valid email address.', 'give' ),
570 - ),
571 - 'give_first' => array(
696 + ],
697 + 'give_first' => [
572 698 'error_id' => 'invalid_first_name',
573 699 'error_message' => __( 'Please enter your first name.', 'give' ),
574 - ),
575 - );
700 + ],
701 + ];
576 702
577 703 $name_title_prefix = give_is_name_title_prefix_required( $form_id );
578 704 if ( $name_title_prefix ) {
579 - $required_fields['give_title'] = array(
705 + $required_fields['give_title'] = [
580 706 'error_id' => 'invalid_title',
581 707 'error_message' => __( 'Please enter your title.', 'give' ),
582 - );
708 + ];
583 709 }
584 710
711 + // If credit card fields related actions exists then check for the cc fields validations.
712 + if (
713 + has_action( "give_{$payment_mode}_cc_form", 'give_get_cc_form' ) ||
714 + has_action( 'give_cc_form', 'give_get_cc_form' )
715 + ) {
716 +
717 + // Validate card number field for empty check.
718 + if (
719 + isset( $posted_data['card_number'] ) &&
720 + empty( $posted_data['card_number'] )
721 + ) {
722 + $required_fields['card_number'] = [
723 + 'error_id' => 'empty_card_number',
724 + 'error_message' => __( 'Please enter a credit card number.', 'give' ),
725 + ];
726 + }
727 +
728 + // Validate card cvc field for empty check.
729 + if (
730 + isset( $posted_data['card_cvc'] ) &&
731 + empty( $posted_data['card_cvc'] )
732 + ) {
733 + $required_fields['card_cvc'] = [
734 + 'error_id' => 'empty_card_cvc',
735 + 'error_message' => __( 'Please enter a credit card CVC information.', 'give' ),
736 + ];
737 + }
738 +
739 + // Validate card name field for empty check.
740 + if (
741 + (
742 + isset( $posted_data['give_validate_stripe_payment_fields'] ) &&
743 + '1' === $posted_data['give_validate_stripe_payment_fields'] &&
744 + isset( $posted_data['card_name'] ) &&
745 + empty( $posted_data['card_name'] )
746 + ) ||
747 + (
748 + ! isset( $posted_data['give_validate_stripe_payment_fields'] ) &&
749 + isset( $posted_data['card_name'] ) &&
750 + empty( $posted_data['card_name'] )
751 + )
752 + ) {
753 + $required_fields['card_name'] = [
754 + 'error_id' => 'empty_card_name',
755 + 'error_message' => __( 'Please enter a name of your credit card account holder.', 'give' ),
756 + ];
757 + }
758 +
759 + // Validate card expiry field for empty check.
760 + if (
761 + isset( $posted_data['card_expiry'] ) &&
762 + empty( $posted_data['card_expiry'] )
763 + ) {
764 + $required_fields['card_expiry'] = [
765 + 'error_id' => 'empty_card_expiry',
766 + 'error_message' => __( 'Please enter a credit card expiry date.', 'give' ),
767 + ];
768 + }
769 + }
770 +
585 771 $require_address = give_require_billing_address( $payment_mode );
586 772
587 773 if ( $require_address ) {
588 - $required_fields['card_address'] = array(
774 + $required_fields['card_address'] = [
589 775 'error_id' => 'invalid_card_address',
590 776 'error_message' => __( 'Please enter your primary billing address.', 'give' ),
591 - );
592 - $required_fields['card_zip'] = array(
777 + ];
778 + $required_fields['card_zip'] = [
593 779 'error_id' => 'invalid_zip_code',
594 780 'error_message' => __( 'Please enter your zip / postal code.', 'give' ),
595 - );
596 - $required_fields['card_city'] = array(
781 + ];
782 + $required_fields['card_city'] = [
597 783 'error_id' => 'invalid_city',
598 784 'error_message' => __( 'Please enter your billing city.', 'give' ),
599 - );
600 - $required_fields['billing_country'] = array(
785 + ];
786 + $required_fields['billing_country'] = [
601 787 'error_id' => 'invalid_country',
602 788 'error_message' => __( 'Please select your billing country.', 'give' ),
603 - );
789 + ];
604 790
605 -
606 - $required_fields['card_state'] = array(
791 + $required_fields['card_state'] = [
607 792 'error_id' => 'invalid_state',
608 793 'error_message' => __( 'Please enter billing state / province / County.', 'give' ),
609 - );
794 + ];
610 795
611 796 $country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
612 797
613 798 // Check if billing country already exists.
@@ -623,8 +808,14 @@
623 808 if ( array_key_exists( $country, give_city_not_required_country_list() ) ) {
624 809 // If states is empty remove the required fields of city in billing cart.
625 810 unset( $required_fields['card_city'] );
626 811 }
812 +
813 + // Check if country is without post codes.
814 + if ( array_key_exists( $country, give_get_country_list_without_postcodes() ) ) {
815 + // If country is on the list, zip code is not required.
816 + unset( $required_fields['card_zip'] );
817 + }
627 818 }
628 819 } // End if().
629 820
630 821 if ( give_is_company_field_enabled( $form_id ) ) {
@@ -632,27 +823,34 @@
632 823 $global_setting = give_get_option( 'company_field' );
633 824
634 825 $is_company_field_required = false;
635 826
636 - if ( ! empty( $form_option ) && give_is_setting_enabled( $form_option, array( 'required' ) ) ) {
827 + if ( ! empty( $form_option ) && give_is_setting_enabled( $form_option, [ 'required' ] ) ) {
637 828 $is_company_field_required = true;
638 829
639 - } elseif ( 'global' === $form_option && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
830 + } elseif ( 'global' === $form_option && give_is_setting_enabled( $global_setting, [ 'required' ] ) ) {
640 831 $is_company_field_required = true;
641 832
642 - } elseif ( empty( $form_option ) && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
833 + } elseif ( empty( $form_option ) && give_is_setting_enabled( $global_setting, [ 'required' ] ) ) {
643 834 $is_company_field_required = true;
644 835
645 836 }
646 837
647 838 if ( $is_company_field_required ) {
648 - $required_fields['give_company_name'] = array(
839 + $required_fields['give_company_name'] = [
649 840 'error_id' => 'invalid_company',
650 841 'error_message' => __( 'Please enter Company Name.', 'give' ),
651 - );
842 + ];
652 843 }
653 844 }
654 845
846 + if ( give_is_last_name_required( $form_id ) ) {
847 + $required_fields['give_last'] = [
848 + 'error_id' => 'invalid_last_name',
849 + 'error_message' => __( 'Please enter your last name.', 'give' ),
850 + ];
851 + }
852 +
655 853 /**
656 854 * Filters the donation form required field.
657 855 *
658 856 * @since 1.7
@@ -689,8 +887,9 @@
689 887 /**
690 888 * Donation Form Validate Logged In User.
691 889 *
692 890 * @access private
891 + * @since 4.16.7.2 Sanitize first and last name values when falling back to stored user data.
693 892 * @since 1.0
694 893 *
695 894 * @return array
696 895 */
@@ -700,15 +899,15 @@
700 899 $user_id = get_current_user_id();
701 900 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
702 901
703 902 // Start empty array to collect valid user data.
704 - $valid_user_data = array(
903 + $valid_user_data = [
705 904
706 905 // Assume there will be errors.
707 906 'user_id' => - 1,
708 - );
907 + ];
709 908
710 - // Proceed on;y, if valid $user_id found.
909 + // Proceed only, if valid $user_id found.
711 910 if ( $user_id > 0 ) {
712 911
713 912 // Get the logged in user data.
714 913 $user_data = get_userdata( $user_id );
@@ -717,20 +916,27 @@
717 916 give_validate_required_form_fields( $form_id );
718 917
719 918 // Verify data.
720 919 if ( is_object( $user_data ) && $user_data->ID > 0 ) {
721 -
722 920 // Collected logged in user data.
723 - $valid_user_data = array(
921 + $valid_user_data = [
724 922 'user_id' => $user_id,
725 - 'user_email' => ! empty( $post_data['give_email'] ) ? sanitize_email( $post_data['give_email'] ) : $user_data->user_email,
726 - 'user_first' => ! empty( $post_data['give_first'] ) ? $post_data['give_first'] : $user_data->first_name,
727 - 'user_last' => ! empty( $post_data['give_last'] ) ? $post_data['give_last'] : $user_data->last_name,
728 - );
923 + 'user_email' => ! empty( $post_data['give_email'] )
924 + ? sanitize_email( $post_data['give_email'] )
925 + : $user_data->user_email,
926 + 'user_first' => ! empty( $post_data['give_first'] )
927 + ? give_clean( $post_data['give_first'] )
928 + : give_clean( $user_data->first_name ),
929 + 'user_last' => ! empty( $post_data['give_last'] )
930 + ? give_clean( $post_data['give_last'] )
931 + : give_clean( $user_data->last_name ),
932 + ];
729 933
730 934 // Validate essential form fields.
731 935 give_donation_form_validate_name_fields( $post_data );
732 936
937 + give_check_logged_in_user_for_existing_email( $valid_user_data );
938 +
733 939 if ( ! is_email( $valid_user_data['user_email'] ) ) {
734 940 give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
735 941 }
736 942 } else {
@@ -747,8 +953,9 @@
747 953 /**
748 954 * Donate Form Validate New User
749 955 *
750 956 * @access private
957 + * @since 4.16.6 Flag data as coming from the checkout registration flow.
751 958 * @since 1.0
752 959 *
753 960 * @return array
754 961 */
@@ -754,9 +961,9 @@
754 961 */
755 962 function give_donation_form_validate_new_user() {
756 963 // Default user data.
757 964 $auto_generated_password = wp_generate_password();
758 - $default_user_data = array(
965 + $default_user_data = [
759 966 'give-form-id' => '',
760 967 'user_id' => - 1, // Assume there will be errors.
761 968 'user_first' => '',
762 969 'user_last' => '',
@@ -763,9 +970,9 @@
763 970 'give_user_login' => false,
764 971 'give_email' => false,
765 972 'give_user_pass' => $auto_generated_password,
766 973 'give_user_pass_confirm' => $auto_generated_password,
767 - );
974 + ];
768 975
769 976 // Get data.
770 977 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
771 978 $user_data = wp_parse_args( $post_data, $default_user_data );
@@ -774,9 +981,9 @@
774 981 $nonce = ! empty( $post_data['give-form-user-register-hash'] ) ? $post_data['give-form-user-register-hash'] : '';
775 982
776 983 // Validate user creation nonce.
777 984 if ( ! wp_verify_nonce( $nonce, "give_form_create_user_nonce_{$form_id}" ) ) {
778 - give_set_error( 'invalid_nonce', __( 'Nonce verification has failed.', 'give' ) );
985 + 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' ) );
779 986 }
780 987
781 988 $registering_new_user = false;
782 989
@@ -782,9 +989,9 @@
782 989
783 990 give_donation_form_validate_name_fields( $user_data );
784 991
785 992 // Start an empty array to collect valid user data.
786 - $valid_user_data = array(
993 + $valid_user_data = [
787 994
788 995 // Assume there will be errors.
789 996 'user_id' => - 1,
790 997
@@ -795,9 +1002,9 @@
795 1002 'user_last' => $user_data['give_last'],
796 1003
797 1004 // Get Password.
798 1005 'user_pass' => $user_data['give_user_pass'],
799 - );
1006 + ];
800 1007
801 1008 // Validate Required Form Fields.
802 1009 give_validate_required_form_fields( $form_id );
803 1010
@@ -808,8 +1015,11 @@
808 1015 if ( give_validate_user_email( $user_data['give_email'], $registering_new_user ) ) {
809 1016 $valid_user_data['user_email'] = $user_data['give_email'];
810 1017 }
811 1018
1019 + // Mark this data as coming from the nonce-verified checkout flow.
1020 + $valid_user_data['give_donation_checkout_registration'] = true;
1021 +
812 1022 return $valid_user_data;
813 1023 }
814 1024
815 1025 /**
@@ -815,8 +1025,9 @@
815 1025 /**
816 1026 * Donation Form Validate User Login
817 1027 *
818 1028 * @access private
1029 + * @since 4.16.7 Authenticate via wp_authenticate() and return a single generic error.
819 1030 * @since 1.0
820 1031 *
821 1032 * @return array
822 1033 */
@@ -824,75 +1035,69 @@
824 1035
825 1036 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
826 1037
827 1038 // Start an array to collect valid user data.
828 - $valid_user_data = array(
1039 + $valid_user_data = [
829 1040
830 1041 // Assume there will be errors.
831 1042 'user_id' => - 1,
832 - );
1043 + ];
833 1044
834 1045 // Bailout, if Username is empty.
835 1046 if ( empty( $post_data['give_user_login'] ) ) {
836 - give_set_error( 'must_log_in', __( 'You must register or login to complete your donation.', 'give' ) );
1047 + give_set_error( 'must_log_in', __( 'Please enter your username or email to log in.', 'give' ) );
837 1048
838 1049 return $valid_user_data;
839 1050 }
840 1051
841 1052 $give_user_login = strip_tags( $post_data['give_user_login'] );
842 - if ( is_email( $give_user_login ) ) {
843 - // Get the user data by email.
844 - $user_data = get_user_by( 'email', $give_user_login );
845 - } else {
846 - // Get the user data by login.
847 - $user_data = get_user_by( 'login', $give_user_login );
1053 +
1054 + // Bailout, if Password is empty.
1055 + if ( empty( $post_data['give_user_pass'] ) ) {
1056 + give_set_error( 'password_empty', __( 'Enter a password.', 'give' ) );
1057 + return $valid_user_data;
848 1058 }
849 1059
850 - // Check if user exists.
851 - if ( $user_data ) {
1060 + // Authenticate through WordPress's login machinery so its authentication
1061 + // hooks, password checks, and failed-login actions all apply.
1062 + $user_data = wp_authenticate( $give_user_login, $post_data['give_user_pass'] );
852 1063
853 - // Get password.
854 - $user_pass = ! empty( $post_data['give_user_pass'] ) ? $post_data['give_user_pass'] : false;
1064 + if ( is_wp_error( $user_data ) ) {
855 1065
856 - // Check user_pass.
857 - if ( $user_pass ) {
1066 + $core_auth_error_codes = [
1067 + 'incorrect_password',
1068 + 'invalid_username',
1069 + 'invalid_email',
1070 + 'empty_username',
1071 + 'empty_password',
1072 + ];
858 1073
859 - // Check if password is valid.
860 - if ( ! wp_check_password( $user_pass, $user_data->user_pass, $user_data->ID ) ) {
1074 + if ( in_array( $user_data->get_error_code(), $core_auth_error_codes, true ) ) {
1075 + // A single generic message for an unknown login and a wrong password.
1076 + $error_message = __( 'The login/password does not match or is incorrect.', 'give' );
1077 + } else {
1078 + // Any other error comes from an authentication hook; surface its message.
1079 + $error_message = wp_strip_all_tags( $user_data->get_error_message() );
861 1080
862 - $current_page_url = site_url() . '/' . get_page_uri();
1081 + if ( '' === $error_message ) {
1082 + $error_message = __( 'The login/password does not match or is incorrect.', 'give' );
1083 + }
1084 + }
863 1085
864 - // Incorrect password.
865 - give_set_error(
866 - 'password_incorrect',
867 - sprintf(
868 - '%1$s <a href="%2$s">%3$s</a>',
869 - __( 'The password you entered is incorrect.', 'give' ),
870 - wp_lostpassword_url( $current_page_url ),
871 - __( 'Reset Password', 'give' )
872 - )
873 - );
1086 + give_set_error( 'invalid_credentials', $error_message );
874 1087
875 - } else {
1088 + return $valid_user_data;
1089 + }
876 1090
877 - // Repopulate the valid user data array.
878 - $valid_user_data = array(
879 - 'user_id' => $user_data->ID,
880 - 'user_login' => $user_data->user_login,
881 - 'user_email' => $user_data->user_email,
882 - 'user_first' => $user_data->first_name,
883 - 'user_last' => $user_data->last_name,
884 - 'user_pass' => $user_pass,
885 - );
886 - }
887 - } else {
888 - // Empty password.
889 - give_set_error( 'password_empty', __( 'Enter a password.', 'give' ) );
890 - }
891 - } else {
892 - // No username.
893 - give_set_error( 'username_incorrect', __( 'The username you entered does not exist.', 'give' ) );
894 - } // End if().
1091 + // Repopulate the valid user data array.
1092 + $valid_user_data = [
1093 + 'user_id' => $user_data->ID,
1094 + 'user_login' => $user_data->user_login,
1095 + 'user_email' => $user_data->user_email,
1096 + 'user_first' => $user_data->first_name,
1097 + 'user_last' => $user_data->last_name,
1098 + 'user_pass' => $post_data['give_user_pass'],
1099 + ];
895 1100
896 1101 return $valid_user_data;
897 1102 }
898 1103
@@ -909,12 +1114,12 @@
909 1114 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
910 1115 $form_id = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
911 1116
912 1117 // Start an array to collect valid user data.
913 - $valid_user_data = array(
1118 + $valid_user_data = [
914 1119 // Set a default id for guests.
915 1120 'user_id' => 0,
916 - );
1121 + ];
917 1122
918 1123 // Validate name fields.
919 1124 give_donation_form_validate_name_fields( $post_data );
920 1125
@@ -940,10 +1145,20 @@
940 1145
941 1146 // Get user_id from donor if exist.
942 1147 $donor = new Give_Donor( $guest_email );
943 1148
944 - if ( $donor->id && $donor->user_id ) {
1149 + if ( $donor->id ) {
1150 + $donor_email_index = array_search(
1151 + strtolower( $guest_email ),
1152 + array_map( 'strtolower', $donor->emails ),
1153 + true
1154 + );
1155 +
945 1156 $valid_user_data['user_id'] = $donor->user_id;
1157 +
1158 + // Set email to original format.
1159 + // @see https://github.com/impress-org/give/issues/4025
1160 + $valid_user_data['user_email'] = $donor->emails[ $donor_email_index ];
946 1161 }
947 1162 }
948 1163 } else {
949 1164 // No email.
@@ -962,9 +1177,9 @@
962 1177 * @since 1.0
963 1178 *
964 1179 * @return integer
965 1180 */
966 -function give_register_and_login_new_user( $user_data = array() ) {
1181 +function give_register_and_login_new_user( $user_data = [] ) {
967 1182 // Verify the array.
968 1183 if ( empty( $user_data ) ) {
969 1184 return - 1;
970 1185 }
@@ -972,17 +1187,21 @@
972 1187 if ( give_get_errors() ) {
973 1188 return - 1;
974 1189 }
975 1190
976 - $user_args = apply_filters( 'give_insert_user_args', array(
977 - 'user_login' => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
978 - 'user_pass' => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
979 - 'user_email' => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
980 - 'first_name' => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
981 - 'last_name' => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
982 - 'user_registered' => date( 'Y-m-d H:i:s' ),
983 - 'role' => give_get_option( 'donor_default_user_role', 'give_donor' ),
984 - ), $user_data );
1191 + $user_args = apply_filters(
1192 + 'give_insert_user_args',
1193 + [
1194 + 'user_login' => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
1195 + 'user_pass' => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
1196 + 'user_email' => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
1197 + 'first_name' => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
1198 + 'last_name' => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
1199 + 'user_registered' => date( 'Y-m-d H:i:s' ),
1200 + 'role' => give_get_option( 'donor_default_user_role', 'give_donor' ),
1201 + ],
1202 + $user_data
1203 + );
985 1204
986 1205 // Insert new user.
987 1206 $user_id = wp_insert_user( $user_args );
988 1207
@@ -1022,53 +1241,47 @@
1022 1241
1023 1242 /**
1024 1243 * Get Donation Form User
1025 1244 *
1245 + * @since 1.0
1246 + * @since 2.17.1 Do not run validation check for ajax request expect donation validation ajax request.
1247 + *
1026 1248 * @param array $valid_data Valid Data.
1027 1249 *
1028 1250 * @access private
1029 - * @since 1.0
1030 - *
1031 1251 * @return array|bool
1032 1252 */
1033 -function give_get_donation_form_user( $valid_data = array() ) {
1253 +function give_get_donation_form_user( $valid_data = [] ) {
1254 + // Initialize user.
1255 + $user = false;
1256 + $post_data = give_clean($_POST); // WPCS: input var ok, sanitization ok, CSRF ok.
1257 + $is_validating_donation_form_on_ajax = ! empty($_POST['give_ajax']) ? $post_data['give_ajax'] : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
1034 1258
1035 - // Initialize user.
1036 - $user = false;
1037 - $is_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
1038 - $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1259 + if ( $is_validating_donation_form_on_ajax ) {
1260 + // Do not create or login the user during the ajax submission (check for errors only).
1261 + return true;
1262 + } elseif ( is_user_logged_in() ) {
1263 + // Set the valid user as the logged in collected data.
1264 + $user = $valid_data['logged_in_user'];
1265 + } elseif ( true === $valid_data['need_new_user'] || true === $valid_data['need_user_login'] ) {
1266 + // New user registration.
1267 + if ( true === $valid_data['need_new_user'] ) {
1268 + // Set user.
1269 + $user = $valid_data['new_user_data'];
1039 1270
1040 - if ( $is_ajax ) {
1271 + // Register and login new user.
1272 + $user['user_id'] = give_register_and_login_new_user($user);
1273 + } elseif ( true === $valid_data['need_user_login'] ) {
1274 + /**
1275 + * The login form is now processed in the give_process_donation_login() function.
1276 + * This is still here for backwards compatibility.
1277 + * This also allows the old login process to still work if a user removes the checkout login submit button.
1278 + *
1279 + * 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.
1280 + */
1281 + $user = $valid_data['login_user_data'];
1041 1282
1042 - // Do not create or login the user during the ajax submission (check for errors only).
1043 - return true;
1044 - } elseif ( is_user_logged_in() ) {
1045 -
1046 - // Set the valid user as the logged in collected data.
1047 - $user = $valid_data['logged_in_user'];
1048 - } elseif ( true === $valid_data['need_new_user'] || true === $valid_data['need_user_login'] ) {
1049 -
1050 - // New user registration.
1051 - if ( true === $valid_data['need_new_user'] ) {
1052 -
1053 - // Set user.
1054 - $user = $valid_data['new_user_data'];
1055 -
1056 - // Register and login new user.
1057 - $user['user_id'] = give_register_and_login_new_user( $user );
1058 -
1059 - } elseif ( true === $valid_data['need_user_login'] && ! $is_ajax ) {
1060 -
1061 - /**
1062 - * The login form is now processed in the give_process_donation_login() function.
1063 - * This is still here for backwards compatibility.
1064 - * This also allows the old login process to still work if a user removes the checkout login submit button.
1065 - *
1066 - * 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.
1067 - */
1068 - $user = $valid_data['login_user_data'];
1069 -
1070 - // Login user.
1283 + // Login user.
1071 1284 give_log_user_in( $user['user_id'], $user['user_login'], $user['user_pass'] );
1072 1285 }
1073 1286 } // End if().
1074 1287
@@ -1099,9 +1312,9 @@
1099 1312 $user['user_title'] = ! empty( $post_data['give_title'] ) ? strip_tags( trim( $post_data['give_title'] ) ) : '';
1100 1313 }
1101 1314
1102 1315 // Get the user's billing address details.
1103 - $user['address'] = array();
1316 + $user['address'] = [];
1104 1317 $user['address']['line1'] = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : false;
1105 1318 $user['address']['line2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : false;
1106 1319 $user['address']['city'] = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : false;
1107 1320 $user['address']['state'] = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : false;
@@ -1157,9 +1370,9 @@
1157 1370
1158 1371 // Sanitize the values submitted with donation form.
1159 1372 $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1160 1373
1161 - $cc_info = array();
1374 + $cc_info = [];
1162 1375 $cc_info['card_name'] = ! empty( $post_data['card_name'] ) ? $post_data['card_name'] : '';
1163 1376 $cc_info['card_number'] = ! empty( $post_data['card_number'] ) ? $post_data['card_number'] : '';
1164 1377 $cc_info['card_cvc'] = ! empty( $post_data['card_cvc'] ) ? $post_data['card_cvc'] : '';
1165 1378 $cc_info['card_exp_month'] = ! empty( $post_data['card_exp_month'] ) ? $post_data['card_exp_month'] : '';
@@ -1193,9 +1406,9 @@
1193 1406 }
1194 1407
1195 1408 $country_code = strtoupper( $country_code );
1196 1409
1197 - $zip_regex = array(
1410 + $zip_regex = [
1198 1411 'AD' => 'AD\d{3}',
1199 1412 'AM' => '(37)?\d{4}',
1200 1413 'AR' => '^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$',
1201 1414 'AS' => '96799',
@@ -1266,9 +1479,9 @@
1266 1479 'JP' => '\d{3}-\d{4}',
1267 1480 'KE' => '\d{5}',
1268 1481 'KG' => '\d{6}',
1269 1482 'KH' => '\d{5}',
1270 - 'KR' => '\d{3}[\-]\d{3}',
1483 + 'KR' => '\d{5}',
1271 1484 'KW' => '\d{5}',
1272 1485 'KZ' => '\d{6}',
1273 1486 'LA' => '\d{5}',
1274 1487 'LB' => '(\d{4}([ ]?\d{4})?)?',
@@ -1349,9 +1562,9 @@
1349 1562 'YT' => '976\d{2}',
1350 1563 'YU' => '\d{5}',
1351 1564 'ZA' => '\d{4}',
1352 1565 'ZM' => '\d{5}',
1353 - );
1566 + ];
1354 1567
1355 1568 if ( ! isset( $zip_regex[ $country_code ] ) || preg_match( '/' . $zip_regex[ $country_code ] . '/i', $zip ) ) {
1356 1569 $ret = true;
1357 1570 }
@@ -1382,9 +1595,9 @@
1382 1595
1383 1596 if ( $form->is_set_type_donation_form() ) {
1384 1597
1385 1598 // Sanitize donation amount.
1386 - $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => $form_currency ) );
1599 + $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => $form_currency ] );
1387 1600
1388 1601 // Backward compatibility.
1389 1602 if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1390 1603 $post_data['give-price-id'] = 'custom';
@@ -1401,10 +1614,10 @@
1401 1614 return false;
1402 1615 }
1403 1616
1404 1617 // Sanitize donation amount.
1405 - $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => $form_currency ) );
1406 - $variable_price_option_amount = give_maybe_sanitize_amount( give_get_price_option_amount( $post_data['give-form-id'], $post_data['give-price-id'] ), array( 'currency' => $form_currency ) );
1618 + $post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], [ 'currency' => $form_currency ] );
1619 + $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 ] );
1407 1620 $new_price_id = '';
1408 1621
1409 1622 if ( $post_data['give-amount'] === $variable_price_option_amount ) {
1410 1623 return true;
@@ -1438,12 +1651,12 @@
1438 1651 if ( ! $donation_level_matched ) {
1439 1652 give_set_error(
1440 1653 'invalid_donation_amount',
1441 1654 sprintf(
1442 - /* translators: %s: invalid donation amount */
1655 + /* translators: %s: invalid donation amount */
1443 1656 __( 'Donation amount %s is invalid.', 'give' ),
1444 1657 give_currency_filter(
1445 - give_format_amount( $post_data['give-amount'], array( 'sanitize' => false, ) )
1658 + give_format_amount( $post_data['give-amount'], [ 'sanitize' => false ] )
1446 1659 )
1447 1660 )
1448 1661 );
1449 1662 }
@@ -1458,20 +1671,15 @@
1458 1671 *
1459 1672 * @since 2.0
1460 1673 */
1461 1674 function give_validate_required_form_fields( $form_id ) {
1462 -
1463 1675 // Sanitize values submitted with donation form.
1464 - $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1676 + $post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
1677 + $requiredFormFields = give_get_required_fields( $form_id );
1465 1678
1466 1679 // Loop through required fields and show error messages.
1467 - foreach ( give_get_required_fields( $form_id ) as $field_name => $value ) {
1468 -
1469 - // Clean Up Data of the input fields.
1470 - $field_value = $post_data[ $field_name ];
1471 -
1472 - // Check whether the required field is empty, then show the error message.
1473 - if ( in_array( $value, give_get_required_fields( $form_id ), true ) && empty( $field_value ) ) {
1680 + foreach ( $requiredFormFields as $field_name => $value ) {
1681 + if ( empty( $post_data[ $field_name ] ) ) {
1474 1682 give_set_error( $value['error_id'], $value['error_message'] );
1475 1683 }
1476 1684 }
1477 1685 }
@@ -1480,8 +1688,12 @@
1480 1688 * Validates and checks if name fields are valid or not.
1481 1689 *
1482 1690 * @param array $post_data List of post data.
1483 1691 *
1692 + * @since 4.16.7.2 Validate last name field even when omitted.
1693 + * @since 3.16.5 Check if "give_title" is set to prevent PHP warnings
1694 + * @since 3.16.4 Add additional validation for company name field
1695 + * @since 3.16.3 Add additional validations for name title prefix field
1484 1696 * @since 2.1
1485 1697 *
1486 1698 * @return void
1487 1699 */
@@ -1486,11 +1698,33 @@
1486 1698 * @return void
1487 1699 */
1488 1700 function give_donation_form_validate_name_fields( $post_data ) {
1489 1701
1490 - $is_alpha_first_name = ( ! is_email( $post_data['give_first'] ) && ! preg_match( '~[0-9]~', $post_data['give_first'] ) );
1491 - $is_alpha_last_name = ( ! is_email( $post_data['give_last'] ) && ! preg_match( '~[0-9]~', $post_data['give_last'] ) );
1702 + $formId = absint( $post_data['give-form-id'] );
1492 1703
1493 - if ( ! $is_alpha_first_name || ( ! empty( $post_data['give_last'] ) && ! $is_alpha_last_name ) ) {
1494 - give_set_error( 'invalid_name', esc_html__( 'The First Name and Last Name fields cannot contain an email address or numbers.', 'give' ) );
1495 - }
1704 + if (!give_is_name_title_prefix_enabled($formId) && isset($post_data['give_title'])) {
1705 + give_set_error( 'disabled_name_title', esc_html__( 'The name title prefix field is not enabled.', 'give' ) );
1706 + }
1707 +
1708 + if (!give_is_company_field_enabled($formId) && isset($post_data['give_company_name'])) {
1709 + give_set_error( 'disabled_company', esc_html__( 'The company field is not enabled.', 'give' ) );
1710 + }
1711 +
1712 + if (give_is_name_title_prefix_enabled($formId) && isset($post_data['give_title']) && !in_array($post_data['give_title'], array_values(give_get_name_title_prefixes($formId)))) {
1713 + give_set_error( 'invalid_name_title', esc_html__( 'The name title prefix field is not valid.', 'give' ) );
1714 + }
1715 +
1716 + $is_alpha_first_name = ( ! is_email( $post_data['give_first'] ) && ! preg_match( '~[0-9]~', $post_data['give_first'] ) );
1717 +
1718 + $lastName = isset( $post_data['give_last'] ) ? $post_data['give_last'] : '';
1719 + $is_alpha_last_name = ( ! is_email( $lastName ) && ! preg_match( '~[0-9]~', $lastName ) );
1720 +
1721 + $is_alpha_title = ( isset($post_data['give_title']) && ! is_email( $post_data['give_title'] ) && ! preg_match( '~[0-9]~', $post_data['give_title'] ) );
1722 +
1723 + if ( ! $is_alpha_first_name || ( ! empty( $lastName ) && ! $is_alpha_last_name ) || ( ! empty( $post_data['give_title'] ) && ! $is_alpha_title ) ) {
1724 + give_set_error( 'invalid_name', esc_html__( 'The First Name and Last Name fields cannot contain an email address or numbers.', 'give' ) );
1725 + }
1726 +
1727 + if ( give_is_last_name_required( $formId ) && empty( $lastName ) ) {
1728 + give_set_error( 'invalid_last_name', esc_html__( 'Please enter your last name.', 'give' ) );
1729 + }
1496 1730 }