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