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