process-donation.php ➔ give_get_required_fields()   F
last analyzed

Complexity

Conditions 25
Paths 3366

Size

Total Lines 155

Duplication

Lines 36
Ratio 23.23 %

Importance

Changes 0
Metric Value
cc 25
nc 3366
nop 1
dl 36
loc 155
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Process Donation
4
 *
5
 * @package     Give
6
 * @subpackage  Functions
7
 * @copyright   Copyright (c) 2016, GiveWP
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Process Donation Form
19
 *
20
 * Handles the donation form process.
21
 *
22
 * @access private
23
 * @since  1.0
24
 *
25
 * @throws ReflectionException Exception Handling.
26
 *
27
 * @return mixed
28
 */
29
function give_process_donation_form() {
30
31
	// Sanitize Posted Data.
32
	$post_data  = give_clean( $_POST ); // WPCS: input var ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
33
34
	// Check whether the form submitted via AJAX or not.
35
	$is_ajax = isset( $post_data['give_ajax'] );
36
37
	// Verify donation form nonce.
38
	if ( ! give_verify_donation_form_nonce( $post_data['give-form-hash'], $post_data['give-form-id'] ) ) {
39
		if ( $is_ajax ) {
40
			/**
41
			 * Fires when AJAX sends back errors from the donation form.
42
			 *
43
			 * @since 1.0
44
			 */
45
			do_action( 'give_ajax_donation_errors' );
46
			give_die();
47
		} else {
48
			give_send_back_to_checkout();
49
		}
50
	}
51
52
	/**
53
	 * Fires before processing the donation form.
54
	 *
55
	 * @since 1.0
56
	 */
57
	do_action( 'give_pre_process_donation' );
58
59
	// Validate the form $_POST data.
60
	$valid_data = give_donation_form_validate_fields();
61
62
	/**
63
	 * Fires after validating donation form fields.
64
	 *
65
	 * Allow you to hook to donation form errors.
66
	 *
67
	 * @since 1.0
68
	 *
69
	 * @param bool|array $valid_data Validate fields.
70
	 * @param array $deprecated Deprecated Since 2.0.2. Use $_POST instead.
71
	 */
72
	$deprecated = $post_data;
73
	do_action( 'give_checkout_error_checks', $valid_data, $deprecated );
74
75
	// Process the login form.
76
	if ( isset( $post_data['give_login_submit'] ) ) {
77
		give_process_form_login();
78
	}
79
80
	// Validate the user.
81
	$user = give_get_donation_form_user( $valid_data );
0 ignored issues
show
Bug introduced by
It seems like $valid_data defined by give_donation_form_validate_fields() on line 60 can also be of type boolean; however, give_get_donation_form_user() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
82
83
	if ( false === $valid_data || give_get_errors() || ! $user ) {
84
		if ( $is_ajax ) {
85
			/**
86
			 * Fires when AJAX sends back errors from the donation form.
87
			 *
88
			 * @since 1.0
89
			 */
90
			do_action( 'give_ajax_donation_errors' );
91
			give_die();
92
		} else {
93
			return false;
94
		}
95
	}
96
97
	// If AJAX send back success to proceed with form submission.
98
	if ( $is_ajax ) {
99
		echo 'success';
100
		give_die();
101
	}
102
103
	/**
104
	 * Fires action after donation form field validated.
105
	 *
106
	 * @since 2.2.0
107
	 */
108
	do_action( 'give_process_donation_after_validation' );
109
110
	// Setup user information.
111
	$user_info = array(
112
		'id'         => $user['user_id'],
113
		'title'      => $user['user_title'],
114
		'email'      => $user['user_email'],
115
		'first_name' => $user['user_first'],
116
		'last_name'  => $user['user_last'],
117
		'address'    => $user['address'],
118
	);
119
120
	$auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
121
122
	// Donation form ID.
123
	$form_id = isset( $post_data['give-form-id'] ) ? absint( $post_data['give-form-id'] ) : 0;
124
125
	$price = isset( $post_data['give-amount'] ) ?
126
		(float) apply_filters( 'give_donation_total', give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => give_get_currency( $form_id ) ) ) ) :
127
		'0.00';
128
	$purchase_key = strtolower( md5( $user['user_email'] . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'give', true ) ) );
129
130
	/**
131
	 * Update donation Purchase key.
132
	 *
133
	 * Use this filter to update default donation purchase key
134
	 * and add prefix in Invoice.
135
	 *
136
	 * @since 2.2.4
137
	 *
138
	 * @param string $purchase_key
139
	 * @param string $gateway
140
	 * @param string $purchase_key
141
	 *
142
	 * @return string $purchase_key
143
	 */
144
	$purchase_key = apply_filters(
145
		'give_donation_purchase_key',
146
		$purchase_key,
147
		$valid_data['gateway'],
148
		// Use this purchase key value if you want to generate custom donation purchase key
149
		// because donation purchase key editable by filters and you may get unedited donation purchase key.
150
		$purchase_key
151
	);
152
153
	// Setup donation information.
154
	$donation_data = array(
155
		'price'         => $price,
156
		'purchase_key'  => $purchase_key,
157
		'user_email'    => $user['user_email'],
158
		'date'          => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
159
		'user_info'     => stripslashes_deep( $user_info ),
160
		'post_data'     => $post_data,
161
		'gateway'       => $valid_data['gateway'],
162
		'card_info'     => $valid_data['cc_info'],
163
	);
164
165
	// Add the user data for hooks.
166
	$valid_data['user'] = $user;
167
168
	/**
169
	 * Fires before donation form gateway.
170
	 *
171
	 * Allow you to hook to donation form before the gateway.
172
	 *
173
	 * @since 1.0
174
	 *
175
	 * @param array      $post_data  Array of variables passed via the HTTP POST.
176
	 * @param array      $user_info  Array containing basic user information.
177
	 * @param bool|array $valid_data Validate fields.
178
	 */
179
	do_action( 'give_checkout_before_gateway', $post_data, $user_info, $valid_data );
180
181
	// Sanity check for price.
182
	if ( ! $donation_data['price'] ) {
183
		// Revert to manual.
184
		$donation_data['gateway'] = 'manual';
185
		$_POST['give-gateway']    = 'manual';
186
	}
187
188
	/**
189
	 * Allow the donation data to be modified before it is sent to the gateway.
190
	 *
191
	 * @since 1.7
192
	 */
193
	$donation_data = apply_filters( 'give_donation_data_before_gateway', $donation_data, $valid_data );
194
195
	// Setup the data we're storing in the donation session.
196
	$session_data = $donation_data;
197
198
	// Make sure credit card numbers are never stored in sessions.
199
	unset( $session_data['card_info']['card_number'] );
200
	unset( $session_data['post_data']['card_number'] );
201
202
	// Used for showing data to non logged-in users after donation, and for other plugins needing donation data.
203
	give_set_purchase_session( $session_data );
204
205
	// Send info to the gateway for payment processing.
206
	give_send_to_gateway( $donation_data['gateway'], $donation_data );
207
	give_die();
208
}
209
210
add_action( 'give_purchase', 'give_process_donation_form' );
211
add_action( 'wp_ajax_give_process_donation', 'give_process_donation_form' );
212
add_action( 'wp_ajax_nopriv_give_process_donation', 'give_process_donation_form' );
213
214
/**
215
 * Verify that when a logged in user makes a donation that the email address used doesn't belong to a different customer.
216
 *
217
 * @since  1.7
218
 *
219
 * @param  array $valid_data Validated data submitted for the donation.
220
 *
221
 * @return void
222
 */
223
function give_check_logged_in_user_for_existing_email( $valid_data ) {
224
225
	// Verify that the email address belongs to this customer.
226
	if ( is_user_logged_in() ) {
227
228
		$submitted_email = $valid_data['logged_in_user']['user_email'];
229
		$donor           = new Give_Donor( get_current_user_id(), true );
230
231
		// If this email address is not registered with this customer, see if it belongs to any other customer.
232
		if (
233
			$submitted_email !== $donor->email
234
			&& ( is_array( $donor->emails ) && ! in_array( $submitted_email, $donor->emails, true ) )
235
		) {
236
			$found_donor = new Give_Donor( $submitted_email );
237
238
			if ( $found_donor->id > 0 ) {
239
				give_set_error(
240
					'give-customer-email-exists',
241
					sprintf(
242
						/* translators: 1. Donor Email, 2. Submitted Email */
243
						__( 'You are logged in as %1$s, and are submitting a donation as %2$s, which is an existing donor. To ensure that the email address is tied to the correct donor, please submit this donation from a logged-out browser, or choose another email address.', 'give' ),
244
						$donor->email,
245
						$submitted_email
246
					)
247
				);
248
			}
249
		}
250
	}
251
}
252
253
add_action( 'give_checkout_error_checks', 'give_check_logged_in_user_for_existing_email', 10, 1 );
254
255
/**
256
 * Process the checkout login form
257
 *
258
 * @access private
259
 * @since  1.0
260
 *
261
 * @return void
262
 */
263
function give_process_form_login() {
264
265
	$is_ajax   = ! empty( $_POST['give_ajax'] ) ? give_clean( $_POST['give_ajax'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
266
	$referrer  = wp_get_referer();
267
	$user_data = give_donation_form_validate_user_login();
268
269
	if ( give_get_errors() || $user_data['user_id'] < 1 ) {
270
		if ( $is_ajax ) {
271
			/**
272
			 * Fires when AJAX sends back errors from the donation form.
273
			 *
274
			 * @since 1.0
275
			 */
276
			ob_start();
277
			do_action( 'give_ajax_donation_errors' );
278
			$message = ob_get_contents();
279
			ob_end_clean();
280
			wp_send_json_error( $message );
281
		} else {
282
			wp_safe_redirect( $referrer );
283
			exit;
284
		}
285
	}
286
287
	give_log_user_in( $user_data['user_id'], $user_data['user_login'], $user_data['user_pass'] );
288
289
	if ( $is_ajax ) {
290
		$message = Give()->notices->print_frontend_notice(
291
			sprintf(
292
				/* translators: %s: user first name */
293
				esc_html__( 'Welcome %s! You have successfully logged into your account.', 'give' ),
294
				( ! empty( $user_data['user_first'] ) ) ? $user_data['user_first'] : $user_data['user_login']
295
			),
296
			false,
297
			'success'
298
		);
299
300
		wp_send_json_success( $message );
301
	} else {
302
		wp_safe_redirect( $referrer );
303
	}
304
}
305
306
add_action( 'wp_ajax_give_process_donation_login', 'give_process_form_login' );
307
add_action( 'wp_ajax_nopriv_give_process_donation_login', 'give_process_form_login' );
308
309
/**
310
 * Donation Form Validate Fields.
311
 *
312
 * @access private
313
 * @since  1.0
314
 *
315
 * @return bool|array
316
 */
317
function give_donation_form_validate_fields() {
318
319
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
320
321
	// Validate Honeypot First.
322
	if ( ! empty( $post_data['give-honeypot'] ) ) {
323
		give_set_error( 'invalid_honeypot', esc_html__( 'Honeypot field detected. Go away bad bot!', 'give' ) );
324
	}
325
326
	// Check spam detect.
327
	if (
328
		isset( $post_data['action'] )
329
		&& give_is_setting_enabled( give_get_option( 'akismet_spam_protection' ) )
330
		&& give_is_spam_donation()
331
	) {
332
		give_set_error( 'spam_donation', __( 'This donation has been flagged as spam. Please try again.', 'give' ) );
333
	}
334
335
	// Start an array to collect valid data.
336
	$valid_data = array(
337
		'gateway'          => give_donation_form_validate_gateway(), // Gateway fallback (amount is validated here).
338
		'need_new_user'    => false,     // New user flag.
339
		'need_user_login'  => false,     // Login user flag.
340
		'logged_user_data' => array(),   // Logged user collected data.
341
		'new_user_data'    => array(),   // New user collected data.
342
		'login_user_data'  => array(),   // Login user collected data.
343
		'guest_user_data'  => array(),   // Guest user collected data.
344
		'cc_info'          => give_donation_form_validate_cc(), // Credit card info.
345
	);
346
347
	$form_id = intval( $post_data['give-form-id'] );
348
349
	// Validate agree to terms.
350
	if ( give_is_terms_enabled( $form_id ) ) {
351
		give_donation_form_validate_agree_to_terms();
352
	}
353
354
	if ( is_user_logged_in() ) {
355
356
		// Collect logged in user data.
357
		$valid_data['logged_in_user'] = give_donation_form_validate_logged_in_user();
358
	} elseif (
359
		isset( $post_data['give-purchase-var'] ) &&
360
		'needs-to-register' === $post_data['give-purchase-var'] &&
361
		! empty( $post_data['give_create_account'] )
362
	) {
363
364
		// Set new user registration as required.
365
		$valid_data['need_new_user'] = true;
366
367
		// Validate new user data.
368
		$valid_data['new_user_data'] = give_donation_form_validate_new_user();
369
	} elseif (
370
		isset( $post_data['give-purchase-var'] ) &&
371
		'needs-to-login' === $post_data['give-purchase-var']
372
	) {
373
374
		// Set user login as required.
375
		$valid_data['need_user_login'] = true;
376
377
		// Validate users login info.
378
		$valid_data['login_user_data'] = give_donation_form_validate_user_login();
379
	} else {
380
381
		// Not registering or logging in, so setup guest user data.
382
		$valid_data['guest_user_data'] = give_donation_form_validate_guest_user();
383
	}
384
385
	// Return collected data.
386
	return $valid_data;
387
}
388
389
/**
390
 * Detect spam donation.
391
 *
392
 * @since 1.8.14
393
 *
394
 * @return bool|mixed
395
 */
396
function give_is_spam_donation() {
397
	$spam = false;
398
399
	$user_agent = (string) isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '';
0 ignored issues
show
introduced by
Due to using Batcache, server side based client related logic will not work, use JS instead.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_SERVER
Loading history...
400
401
	if ( strlen( $user_agent ) < 2 ) {
402
		$spam = true;
403
	}
404
405
	// Allow developer to customized Akismet spam detect API call and it's response.
406
	return apply_filters( 'give_spam', $spam );
407
}
408
409
/**
410
 * Donation Form Validate Gateway
411
 *
412
 * Validate the gateway and donation amount.
413
 *
414
 * @access private
415
 * @since  1.0
416
 *
417
 * @return string
418
 */
419
function give_donation_form_validate_gateway() {
420
421
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
422
	$form_id   = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
423
	$amount    = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'] ) : 0;
424
	$gateway   = ! empty( $post_data['give-gateway'] ) ? $post_data['give-gateway'] : 0;
425
426
	// Bailout, if payment gateway is not submitted with donation form data.
427
	if ( empty( $gateway ) ) {
428
429
		give_set_error( 'empty_gateway', __( 'The donation form will process with a valid payment gateway.', 'give' ) );
430
431
	} elseif ( ! give_is_gateway_active( $gateway ) ) {
432
433
		give_set_error( 'invalid_gateway', __( 'The selected payment gateway is not enabled.', 'give' ) );
434
435
	} elseif ( empty( $amount ) ) {
436
437
		give_set_error( 'invalid_donation_amount', __( 'Please insert a valid donation amount.', 'give' ) );
438
439
	} elseif ( ! give_verify_minimum_price( 'minimum' ) ) {
440
441
		give_set_error(
442
			'invalid_donation_minimum',
443
			sprintf(
444
				/* translators: %s: minimum donation amount */
445
				__( 'This form has a minimum donation amount of %s.', 'give' ),
446
				give_currency_filter(
447
					give_format_amount( give_get_form_minimum_price( $form_id ),
0 ignored issues
show
Documentation introduced by
give_get_form_minimum_price($form_id) is of type false|double, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
448
						array(
449
							'sanitize' => false,
450
						)
451
					)
452
				)
453
			)
454
		);
455
	} elseif ( ! give_verify_minimum_price( 'maximum' ) ) {
456
457
		give_set_error(
458
			'invalid_donation_maximum',
459
			sprintf(
460
				/* translators: %s: Maximum donation amount */
461
				__( 'This form has a maximum donation amount of %s.', 'give' ),
462
				give_currency_filter(
463
					give_format_amount( give_get_form_maximum_price( $form_id ),
0 ignored issues
show
Documentation introduced by
give_get_form_maximum_price($form_id) is of type false|double, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
464
						array(
465
							'sanitize' => false,
466
						)
467
					)
468
				)
469
			)
470
		);
471
	} // End if().
472
473
	return $gateway;
474
475
}
476
477
/**
478
 * Donation Form Validate Minimum or Maximum Donation Amount
479
 *
480
 * @access private
481
 * @since  1.3.6
482
 * @since  2.1 Added support for give maximum amount.
483
 * @since  2.1.3 Added new filter to modify the return value.
484
 *
485
 * @param string $amount_range Which amount needs to verify? minimum or maximum.
486
 *
487
 * @return bool
488
 */
489
function give_verify_minimum_price( $amount_range = 'minimum' ) {
490
491
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
492
	$form_id   = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
493
	$amount    = ! empty( $post_data['give-amount'] ) ? give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => give_get_currency( $form_id ) ) ) : 0;
494
	$price_id  = isset( $post_data['give-price-id'] ) ? absint( $post_data['give-price-id'] ) : '';
495
496
	$variable_prices = give_has_variable_prices( $form_id );
497
	$price_ids       = array_map( 'absint', give_get_variable_price_ids( $form_id ) );
498
	$verified_stat   = false;
499
500
	if ( $variable_prices && in_array( $price_id, $price_ids, true ) ) {
501
502
		$price_level_amount = give_get_price_option_amount( $form_id, $price_id );
503
504
		if ( $price_level_amount == $amount ) {
505
			$verified_stat = true;
506
		}
507
	}
508
509
	if ( ! $verified_stat ) {
510
		switch ( $amount_range ) {
511
			case 'minimum' :
512
				$verified_stat = ( give_get_form_minimum_price( $form_id ) > $amount ) ? false : true;
513
				break;
514
			case 'maximum' :
515
				$verified_stat = ( give_get_form_maximum_price( $form_id ) < $amount ) ? false : true;
516
				break;
517
		}
518
	}
519
520
	/**
521
	 * Filter the verify amount
522
	 *
523
	 * @since 2.1.3
524
	 *
525
	 * @param bool    $verified_stat Was verification passed or not?
526
	 * @param string  $amount_range  Type of the amount.
527
	 * @param integer $form_id       Give Donation Form ID.
528
	 */
529
	return apply_filters( 'give_verify_minimum_maximum_price', $verified_stat, $amount_range, $form_id );
530
}
531
532
/**
533
 * Donation form validate agree to "Terms and Conditions".
534
 *
535
 * @access private
536
 * @since  1.0
537
 *
538
 * @return void
539
 */
540
function give_donation_form_validate_agree_to_terms() {
541
542
	$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.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
543
544
	// Proceed only, if donor agreed to terms.
545
	if ( ! $agree_to_terms ) {
546
547
		// User did not agree.
548
		give_set_error( 'agree_to_terms', apply_filters( 'give_agree_to_terms_text', __( 'You must agree to the terms and conditions.', 'give' ) ) );
549
	}
550
}
551
552
/**
553
 * Donation Form Required Fields.
554
 *
555
 * @access private
556
 * @since  1.0
557
 *
558
 * @param  int $form_id Donation Form ID.
559
 *
560
 * @return array
561
 */
562
function give_get_required_fields( $form_id ) {
563
564
	$posted_data  = give_clean( filter_input_array( INPUT_POST ) );
565
	$payment_mode = give_get_chosen_gateway( $form_id );
566
567
	$required_fields = array(
568
		'give_email' => array(
569
			'error_id'      => 'invalid_email',
570
			'error_message' => __( 'Please enter a valid email address.', 'give' ),
571
		),
572
		'give_first' => array(
573
			'error_id'      => 'invalid_first_name',
574
			'error_message' => __( 'Please enter your first name.', 'give' ),
575
		),
576
	);
577
578
	$name_title_prefix = give_is_name_title_prefix_required( $form_id );
579
	if ( $name_title_prefix ) {
580
		$required_fields['give_title'] = array(
581
			'error_id'      => 'invalid_title',
582
			'error_message' => __( 'Please enter your title.', 'give' ),
583
		);
584
	}
585
	
586
	// If credit card fields related actions exists then check for the cc fields validations.
587
	if (
588
		has_action("give_{$payment_mode}_cc_form", 'give_get_cc_form' ) ||
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
589
		has_action('give_cc_form', 'give_get_cc_form' )
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
590
	) {
591
		
592
		// Validate card number field for empty check.
593 View Code Duplication
		if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
594
			isset( $posted_data['card_number'] ) &&
595
			empty( $posted_data['card_number'] )
596
		) {
597
			$required_fields['card_number'] = array(
598
				'error_id'      => 'empty_card_number',
599
				'error_message' => __( 'Please enter a credit card number.', 'give' ),
600
			);
601
		}
602
		
603
		// Validate card cvc field for empty check.
604 View Code Duplication
		if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
605
			isset( $posted_data['card_cvc'] ) &&
606
			empty( $posted_data['card_cvc'] )
607
		) {
608
			$required_fields['card_cvc'] = array(
609
				'error_id'      => 'empty_card_cvc',
610
				'error_message' => __( 'Please enter a credit card CVC information.', 'give' ),
611
			);
612
		}
613
		
614
		// Validate card name field for empty check.
615 View Code Duplication
		if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
616
			isset( $posted_data['card_name'] ) &&
617
			empty( $posted_data['card_name'] )
618
		) {
619
			$required_fields['card_name'] = array(
620
				'error_id'      => 'empty_card_name',
621
				'error_message' => __( 'Please enter a name of your credit card account holder.', 'give' ),
622
			);
623
		}
624
		
625
		// Validate card expiry field for empty check.
626 View Code Duplication
		if (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
627
			isset( $posted_data['card_expiry'] ) &&
628
			empty( $posted_data['card_expiry'] )
629
		) {
630
			$required_fields['card_expiry'] = array(
631
				'error_id'      => 'empty_card_expiry',
632
				'error_message' => __( 'Please enter a credit card expiry date.', 'give' ),
633
			);
634
		}
635
	}
636
637
	$require_address = give_require_billing_address( $payment_mode );
638
639
	if ( $require_address ) {
640
		$required_fields['card_address']    = array(
641
			'error_id'      => 'invalid_card_address',
642
			'error_message' => __( 'Please enter your primary billing address.', 'give' ),
643
		);
644
		$required_fields['card_zip']        = array(
645
			'error_id'      => 'invalid_zip_code',
646
			'error_message' => __( 'Please enter your zip / postal code.', 'give' ),
647
		);
648
		$required_fields['card_city']       = array(
649
			'error_id'      => 'invalid_city',
650
			'error_message' => __( 'Please enter your billing city.', 'give' ),
651
		);
652
		$required_fields['billing_country'] = array(
653
			'error_id'      => 'invalid_country',
654
			'error_message' => __( 'Please select your billing country.', 'give' ),
655
		);
656
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
657
658
		$required_fields['card_state'] = array(
659
			'error_id'      => 'invalid_state',
660
			'error_message' => __( 'Please enter billing state / province / County.', 'give' ),
661
		);
662
663
		$country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
664
665
		// Check if billing country already exists.
666
		if ( $country ) {
667
668
			// Check if states is empty or not.
669
			if ( array_key_exists( $country, give_states_not_required_country_list() ) ) {
670
				// If states is empty remove the required fields of state in billing cart.
671
				unset( $required_fields['card_state'] );
672
			}
673
674
			// Check if city is empty or not.
675
			if ( array_key_exists( $country, give_city_not_required_country_list() ) ) {
676
				// If states is empty remove the required fields of city in billing cart.
677
				unset( $required_fields['card_city'] );
678
			}
679
		}
680
	} // End if().
681
682
	if ( give_is_company_field_enabled( $form_id ) ) {
683
		$form_option    = give_get_meta( $form_id, '_give_company_field', true );
684
		$global_setting = give_get_option( 'company_field' );
685
686
		$is_company_field_required = false;
687
688
		if ( ! empty( $form_option ) && give_is_setting_enabled( $form_option, array( 'required' ) ) ) {
0 ignored issues
show
Documentation introduced by
array('required') is of type array<integer,string,{"0":"string"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
689
			$is_company_field_required = true;
690
691
		} elseif ( 'global' === $form_option && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
0 ignored issues
show
Documentation introduced by
array('required') is of type array<integer,string,{"0":"string"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
692
			$is_company_field_required = true;
693
694
		} elseif ( empty( $form_option ) && give_is_setting_enabled( $global_setting, array( 'required' ) ) ) {
0 ignored issues
show
Documentation introduced by
array('required') is of type array<integer,string,{"0":"string"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
695
			$is_company_field_required = true;
696
697
		}
698
699
		if ( $is_company_field_required ) {
700
			$required_fields['give_company_name'] = array(
701
				'error_id'      => 'invalid_company',
702
				'error_message' => __( 'Please enter Company Name.', 'give' ),
703
			);
704
		}
705
	}
706
707
	/**
708
	 * Filters the donation form required field.
709
	 *
710
	 * @since 1.7
711
	 */
712
	$required_fields = apply_filters( 'give_donation_form_required_fields', $required_fields, $form_id );
713
714
	return $required_fields;
715
716
}
717
718
/**
719
 * Check if the Billing Address is required
720
 *
721
 * @since  1.0.1
722
 *
723
 * @param string $payment_mode Payment Mode.
724
 *
725
 * @return bool
726
 */
727
function give_require_billing_address( $payment_mode ) {
728
729
	$return          = false;
730
	$billing_country = ! empty( $_POST['billing_country'] ) ? give_clean( $_POST['billing_country'] ) : 0; // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
731
732
	if ( $billing_country || did_action( "give_{$payment_mode}_cc_form" ) || did_action( 'give_cc_form' ) ) {
733
		$return = true;
734
	}
735
736
	// Let payment gateways and other extensions determine if address fields should be required.
737
	return apply_filters( 'give_require_billing_address', $return );
738
739
}
740
741
/**
742
 * Donation Form Validate Logged In User.
743
 *
744
 * @access private
745
 * @since  1.0
746
 *
747
 * @return array
748
 */
749
function give_donation_form_validate_logged_in_user() {
750
751
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
752
	$user_id   = get_current_user_id();
753
	$form_id   = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
754
755
	// Start empty array to collect valid user data.
756
	$valid_user_data = array(
757
758
		// Assume there will be errors.
759
		'user_id' => - 1,
760
	);
761
762
	// Proceed on;y, if valid $user_id found.
763
	if ( $user_id > 0 ) {
764
765
		// Get the logged in user data.
766
		$user_data = get_userdata( $user_id );
767
768
		// Validate Required Form Fields.
769
		give_validate_required_form_fields( $form_id );
770
771
		// Verify data.
772
		if ( is_object( $user_data ) && $user_data->ID > 0 ) {
773
774
			// Collected logged in user data.
775
			$valid_user_data = array(
776
				'user_id'    => $user_id,
777
				'user_email' => ! empty( $post_data['give_email'] ) ? sanitize_email( $post_data['give_email'] ) : $user_data->user_email,
778
				'user_first' => ! empty( $post_data['give_first'] ) ? $post_data['give_first'] : $user_data->first_name,
779
				'user_last'  => ! empty( $post_data['give_last'] ) ? $post_data['give_last'] : $user_data->last_name,
780
			);
781
782
			// Validate essential form fields.
783
			give_donation_form_validate_name_fields( $post_data );
0 ignored issues
show
Bug introduced by
It seems like $post_data defined by give_clean($_POST) on line 751 can also be of type string; however, give_donation_form_validate_name_fields() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
784
785
			if ( ! is_email( $valid_user_data['user_email'] ) ) {
786
				give_set_error( 'email_invalid', esc_html__( 'Invalid email.', 'give' ) );
787
			}
788
		} else {
789
790
			// Set invalid user information error.
791
			give_set_error( 'invalid_user', esc_html__( 'The user information is invalid.', 'give' ) );
792
		}
793
	}
794
795
	// Return user data.
796
	return $valid_user_data;
797
}
798
799
/**
800
 * Donate Form Validate New User
801
 *
802
 * @access private
803
 * @since  1.0
804
 *
805
 * @return array
806
 */
807
function give_donation_form_validate_new_user() {
808
	// Default user data.
809
	$auto_generated_password = wp_generate_password();
810
	$default_user_data       = array(
811
		'give-form-id'           => '',
812
		'user_id'                => - 1, // Assume there will be errors.
813
		'user_first'             => '',
814
		'user_last'              => '',
815
		'give_user_login'        => false,
816
		'give_email'             => false,
817
		'give_user_pass'         => $auto_generated_password,
818
		'give_user_pass_confirm' => $auto_generated_password,
819
	);
820
821
	// Get data.
822
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
823
	$user_data = wp_parse_args( $post_data, $default_user_data );
824
825
	$form_id = absint( $user_data['give-form-id'] );
826
	$nonce   = ! empty( $post_data['give-form-user-register-hash'] ) ? $post_data['give-form-user-register-hash'] : '';
827
828
	// Validate user creation nonce.
829
	if ( ! wp_verify_nonce( $nonce, "give_form_create_user_nonce_{$form_id}" ) ) {
830
		give_set_error( 'invalid_nonce', __( 'Nonce verification has failed.', 'give' ) );
831
	}
832
833
	$registering_new_user = false;
834
835
	give_donation_form_validate_name_fields( $user_data );
836
837
	// Start an empty array to collect valid user data.
838
	$valid_user_data = array(
839
840
		// Assume there will be errors.
841
		'user_id'    => - 1,
842
843
		// Get first name.
844
		'user_first' => $user_data['give_first'],
845
846
		// Get last name.
847
		'user_last'  => $user_data['give_last'],
848
849
		// Get Password.
850
		'user_pass'  => $user_data['give_user_pass'],
851
	);
852
853
	// Validate Required Form Fields.
854
	give_validate_required_form_fields( $form_id );
855
856
	// Set Email as Username.
857
	$valid_user_data['user_login'] = $user_data['give_email'];
858
859
	// Check if we have an email to verify.
860
	if ( give_validate_user_email( $user_data['give_email'], $registering_new_user ) ) {
861
		$valid_user_data['user_email'] = $user_data['give_email'];
862
	}
863
864
	return $valid_user_data;
865
}
866
867
/**
868
 * Donation Form Validate User Login
869
 *
870
 * @access private
871
 * @since  1.0
872
 *
873
 * @return array
874
 */
875
function give_donation_form_validate_user_login() {
876
877
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
878
879
	// Start an array to collect valid user data.
880
	$valid_user_data = array(
881
882
		// Assume there will be errors.
883
		'user_id' => - 1,
884
	);
885
886
	// Bailout, if Username is empty.
887
	if ( empty( $post_data['give_user_login'] ) ) {
888
		give_set_error( 'must_log_in', __( 'You must register or login to complete your donation.', 'give' ) );
889
890
		return $valid_user_data;
891
	}
892
893
	$give_user_login = strip_tags( $post_data['give_user_login'] );
894
	if ( is_email( $give_user_login ) ) {
895
		// Get the user data by email.
896
		$user_data = get_user_by( 'email', $give_user_login );
897
	} else {
898
		// Get the user data by login.
899
		$user_data = get_user_by( 'login', $give_user_login );
900
	}
901
902
	// Check if user exists.
903
	if ( $user_data ) {
904
905
		// Get password.
906
		$user_pass = ! empty( $post_data['give_user_pass'] ) ? $post_data['give_user_pass'] : false;
907
908
		// Check user_pass.
909
		if ( $user_pass ) {
910
911
			// Check if password is valid.
912
			if ( ! wp_check_password( $user_pass, $user_data->user_pass, $user_data->ID ) ) {
913
914
				$current_page_url = site_url() . '/' . get_page_uri();
915
916
				// Incorrect password.
917
				give_set_error(
918
					'password_incorrect',
919
					sprintf(
920
						'%1$s <a href="%2$s">%3$s</a>',
921
						__( 'The password you entered is incorrect.', 'give' ),
922
						wp_lostpassword_url( $current_page_url ),
923
						__( 'Reset Password', 'give' )
924
					)
925
				);
926
927
			} else {
928
929
				// Repopulate the valid user data array.
930
				$valid_user_data = array(
931
					'user_id'    => $user_data->ID,
932
					'user_login' => $user_data->user_login,
933
					'user_email' => $user_data->user_email,
934
					'user_first' => $user_data->first_name,
935
					'user_last'  => $user_data->last_name,
936
					'user_pass'  => $user_pass,
937
				);
938
			}
939
		} else {
940
			// Empty password.
941
			give_set_error( 'password_empty', __( 'Enter a password.', 'give' ) );
942
		}
943
	} else {
944
		// No username.
945
		give_set_error( 'username_incorrect', __( 'The username you entered does not exist.', 'give' ) );
946
	} // End if().
947
948
	return $valid_user_data;
949
}
950
951
/**
952
 * Donation Form Validate Guest User
953
 *
954
 * @access private
955
 * @since  1.0
956
 *
957
 * @return array
958
 */
959
function give_donation_form_validate_guest_user() {
960
961
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
962
	$form_id   = ! empty( $post_data['give-form-id'] ) ? $post_data['give-form-id'] : 0;
963
964
	// Start an array to collect valid user data.
965
	$valid_user_data = array(
966
		// Set a default id for guests.
967
		'user_id' => 0,
968
	);
969
970
	// Validate name fields.
971
	give_donation_form_validate_name_fields( $post_data );
0 ignored issues
show
Bug introduced by
It seems like $post_data defined by give_clean($_POST) on line 961 can also be of type string; however, give_donation_form_validate_name_fields() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
972
973
	// Validate Required Form Fields.
974
	give_validate_required_form_fields( $form_id );
975
976
	// Get the guest email.
977
	$guest_email = ! empty( $post_data['give_email'] ) ? $post_data['give_email'] : false;
978
979
	// Check email.
980
	if ( $guest_email && strlen( $guest_email ) > 0 ) {
981
982
		// Validate email.
983
		if ( ! is_email( $guest_email ) ) {
984
985
			// Invalid email.
986
			give_set_error( 'email_invalid', __( 'Invalid email.', 'give' ) );
987
988
		} else {
989
990
			// All is good to go.
991
			$valid_user_data['user_email'] = $guest_email;
992
993
			// Get user_id from donor if exist.
994
			$donor = new Give_Donor( $guest_email );
995
996
			if ( $donor->id && $donor->user_id ) {
997
				$valid_user_data['user_id'] = $donor->user_id;
998
			}
999
		}
1000
	} else {
1001
		// No email.
1002
		give_set_error( 'email_empty', __( 'Enter an email.', 'give' ) );
1003
	}
1004
1005
	return $valid_user_data;
1006
}
1007
1008
/**
1009
 * Register And Login New User
1010
 *
1011
 * @param array $user_data User Data.
1012
 *
1013
 * @access  private
1014
 * @since   1.0
1015
 *
1016
 * @return  integer
1017
 */
1018
function give_register_and_login_new_user( $user_data = array() ) {
1019
	// Verify the array.
1020
	if ( empty( $user_data ) ) {
1021
		return - 1;
1022
	}
1023
1024
	if ( give_get_errors() ) {
1025
		return - 1;
1026
	}
1027
1028
	$user_args = apply_filters( 'give_insert_user_args', array(
1029
		'user_login'      => isset( $user_data['user_login'] ) ? $user_data['user_login'] : '',
1030
		'user_pass'       => isset( $user_data['user_pass'] ) ? $user_data['user_pass'] : '',
1031
		'user_email'      => isset( $user_data['user_email'] ) ? $user_data['user_email'] : '',
1032
		'first_name'      => isset( $user_data['user_first'] ) ? $user_data['user_first'] : '',
1033
		'last_name'       => isset( $user_data['user_last'] ) ? $user_data['user_last'] : '',
1034
		'user_registered' => date( 'Y-m-d H:i:s' ),
1035
		'role'            => give_get_option( 'donor_default_user_role', 'give_donor' ),
1036
	), $user_data );
1037
1038
	// Insert new user.
1039
	$user_id = wp_insert_user( $user_args );
1040
1041
	// Validate inserted user.
1042
	if ( is_wp_error( $user_id ) ) {
1043
		return - 1;
1044
	}
1045
1046
	// Allow themes and plugins to filter the user data.
1047
	$user_data = apply_filters( 'give_insert_user_data', $user_data, $user_args );
1048
1049
	/**
1050
	 * Fires after inserting user.
1051
	 *
1052
	 * @since 1.0
1053
	 *
1054
	 * @param int $user_id User id.
1055
	 * @param array $user_data Array containing user data.
1056
	 */
1057
	do_action( 'give_insert_user', $user_id, $user_data );
1058
1059
	/**
1060
	 * Filter allow user to alter if user when to login or not when user is register for the first time.
1061
	 *
1062
	 * @since 1.8.13
1063
	 *
1064
	 * return bool True if login with registration and False if only want to register.
1065
	 */
1066
	if ( true === (bool) apply_filters( 'give_log_user_in_on_register', true ) ) {
1067
		// Login new user.
1068
		give_log_user_in( $user_id, $user_data['user_login'], $user_data['user_pass'] );
1069
	}
1070
1071
	// Return user id.
1072
	return $user_id;
1073
}
1074
1075
/**
1076
 * Get Donation Form User
1077
 *
1078
 * @param array $valid_data Valid Data.
1079
 *
1080
 * @access  private
1081
 * @since   1.0
1082
 *
1083
 * @return  array|bool
1084
 */
1085
function give_get_donation_form_user( $valid_data = array() ) {
1086
1087
	// Initialize user.
1088
	$user      = false;
1089
	$is_ajax   = defined( 'DOING_AJAX' ) && DOING_AJAX;
1090
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
1091
1092
	if ( $is_ajax ) {
1093
1094
		// Do not create or login the user during the ajax submission (check for errors only).
1095
		return true;
1096
	} elseif ( is_user_logged_in() ) {
1097
1098
		// Set the valid user as the logged in collected data.
1099
		$user = $valid_data['logged_in_user'];
1100
	} elseif ( true === $valid_data['need_new_user'] || true === $valid_data['need_user_login'] ) {
1101
1102
		// New user registration.
1103
		if ( true === $valid_data['need_new_user'] ) {
1104
1105
			// Set user.
1106
			$user = $valid_data['new_user_data'];
1107
1108
			// Register and login new user.
1109
			$user['user_id'] = give_register_and_login_new_user( $user );
1110
1111
		} elseif ( true === $valid_data['need_user_login'] && ! $is_ajax ) {
1112
1113
			/**
1114
			 * The login form is now processed in the give_process_donation_login() function.
1115
			 * This is still here for backwards compatibility.
1116
			 * This also allows the old login process to still work if a user removes the checkout login submit button.
1117
			 *
1118
			 * 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.
1119
			 */
1120
			$user = $valid_data['login_user_data'];
1121
1122
			// Login user.
1123
			give_log_user_in( $user['user_id'], $user['user_login'], $user['user_pass'] );
1124
		}
1125
	} // End if().
1126
1127
	// Check guest checkout.
1128
	if ( false === $user && false === give_logged_in_only( $post_data['give-form-id'] ) ) {
1129
1130
		// Set user.
1131
		$user = $valid_data['guest_user_data'];
1132
	}
1133
1134
	// Verify we have an user.
1135
	if ( false === $user || empty( $user ) ) {
1136
		return false;
1137
	}
1138
1139
	// Get user first name.
1140 View Code Duplication
	if ( ! isset( $user['user_first'] ) || strlen( trim( $user['user_first'] ) ) < 1 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1141
		$user['user_first'] = isset( $post_data['give_first'] ) ? strip_tags( trim( $post_data['give_first'] ) ) : '';
1142
	}
1143
1144
	// Get user last name.
1145 View Code Duplication
	if ( ! isset( $user['user_last'] ) || strlen( trim( $user['user_last'] ) ) < 1 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1146
		$user['user_last'] = isset( $post_data['give_last'] ) ? strip_tags( trim( $post_data['give_last'] ) ) : '';
1147
	}
1148
1149
	// Add Title Prefix to user information.
1150 View Code Duplication
	if ( empty( $user['user_title'] ) || strlen( trim( $user['user_title'] ) ) < 1 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1151
		$user['user_title'] = ! empty( $post_data['give_title'] ) ? strip_tags( trim( $post_data['give_title'] ) ) : '';
1152
	}
1153
1154
	// Get the user's billing address details.
1155
	$user['address']            = array();
1156
	$user['address']['line1']   = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : false;
1157
	$user['address']['line2']   = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : false;
1158
	$user['address']['city']    = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : false;
1159
	$user['address']['state']   = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : false;
1160
	$user['address']['zip']     = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : false;
1161
	$user['address']['country'] = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : false;
1162
1163
	if ( empty( $user['address']['country'] ) ) {
1164
		$user['address'] = false;
1165
	} // End if().
1166
1167
	// Return valid user.
1168
	return $user;
1169
}
1170
1171
/**
1172
 * Validates the credit card info.
1173
 *
1174
 * @access  private
1175
 * @since   1.0
1176
 *
1177
 * @return  array
1178
 */
1179
function give_donation_form_validate_cc() {
1180
1181
	$card_data = give_get_donation_cc_info();
1182
1183
	// Validate the card zip.
1184
	if ( ! empty( $card_data['card_zip'] ) ) {
1185
		if ( ! give_donation_form_validate_cc_zip( $card_data['card_zip'], $card_data['card_country'] ) ) {
1186
			give_set_error( 'invalid_cc_zip', __( 'The zip / postal code you entered for your billing address is invalid.', 'give' ) );
1187
		}
1188
	}
1189
1190
	// Ensure no spaces.
1191
	if ( ! empty( $card_data['card_number'] ) ) {
1192
		$card_data['card_number'] = str_replace( '+', '', $card_data['card_number'] ); // no "+" signs.
1193
		$card_data['card_number'] = str_replace( ' ', '', $card_data['card_number'] ); // No spaces.
1194
	}
1195
1196
	// This should validate card numbers at some point too.
1197
	return $card_data;
1198
}
1199
1200
/**
1201
 * Get credit card info.
1202
 *
1203
 * @access private
1204
 * @since  1.0
1205
 *
1206
 * @return array
1207
 */
1208
function give_get_donation_cc_info() {
1209
1210
	// Sanitize the values submitted with donation form.
1211
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
1212
1213
	$cc_info                   = array();
1214
	$cc_info['card_name']      = ! empty( $post_data['card_name'] ) ? $post_data['card_name'] : '';
1215
	$cc_info['card_number']    = ! empty( $post_data['card_number'] ) ? $post_data['card_number'] : '';
1216
	$cc_info['card_cvc']       = ! empty( $post_data['card_cvc'] ) ? $post_data['card_cvc'] : '';
1217
	$cc_info['card_exp_month'] = ! empty( $post_data['card_exp_month'] ) ? $post_data['card_exp_month'] : '';
1218
	$cc_info['card_exp_year']  = ! empty( $post_data['card_exp_year'] ) ? $post_data['card_exp_year'] : '';
1219
	$cc_info['card_address']   = ! empty( $post_data['card_address'] ) ? $post_data['card_address'] : '';
1220
	$cc_info['card_address_2'] = ! empty( $post_data['card_address_2'] ) ? $post_data['card_address_2'] : '';
1221
	$cc_info['card_city']      = ! empty( $post_data['card_city'] ) ? $post_data['card_city'] : '';
1222
	$cc_info['card_state']     = ! empty( $post_data['card_state'] ) ? $post_data['card_state'] : '';
1223
	$cc_info['card_country']   = ! empty( $post_data['billing_country'] ) ? $post_data['billing_country'] : '';
1224
	$cc_info['card_zip']       = ! empty( $post_data['card_zip'] ) ? $post_data['card_zip'] : '';
1225
1226
	// Return cc info.
1227
	return $cc_info;
1228
}
1229
1230
/**
1231
 * Validate zip code based on country code
1232
 *
1233
 * @since  1.0
1234
 *
1235
 * @param int    $zip          ZIP Code.
1236
 * @param string $country_code Country Code.
1237
 *
1238
 * @return bool|mixed
1239
 */
1240
function give_donation_form_validate_cc_zip( $zip = 0, $country_code = '' ) {
1241
	$ret = false;
1242
1243
	if ( empty( $zip ) || empty( $country_code ) ) {
1244
		return $ret;
1245
	}
1246
1247
	$country_code = strtoupper( $country_code );
1248
1249
	$zip_regex = array(
1250
		'AD' => 'AD\d{3}',
1251
		'AM' => '(37)?\d{4}',
1252
		'AR' => '^([A-Z]{1}\d{4}[A-Z]{3}|[A-Z]{1}\d{4}|\d{4})$',
1253
		'AS' => '96799',
1254
		'AT' => '\d{4}',
1255
		'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})$',
1256
		'AX' => '22\d{3}',
1257
		'AZ' => '\d{4}',
1258
		'BA' => '\d{5}',
1259
		'BB' => '(BB\d{5})?',
1260
		'BD' => '\d{4}',
1261
		'BE' => '^[1-9]{1}[0-9]{3}$',
1262
		'BG' => '\d{4}',
1263
		'BH' => '((1[0-2]|[2-9])\d{2})?',
1264
		'BM' => '[A-Z]{2}[ ]?[A-Z0-9]{2}',
1265
		'BN' => '[A-Z]{2}[ ]?\d{4}',
1266
		'BR' => '\d{5}[\-]?\d{3}',
1267
		'BY' => '\d{6}',
1268
		'CA' => '^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$',
1269
		'CC' => '6799',
1270
		'CH' => '^[1-9][0-9][0-9][0-9]$',
1271
		'CK' => '\d{4}',
1272
		'CL' => '\d{7}',
1273
		'CN' => '\d{6}',
1274
		'CR' => '\d{4,5}|\d{3}-\d{4}',
1275
		'CS' => '\d{5}',
1276
		'CV' => '\d{4}',
1277
		'CX' => '6798',
1278
		'CY' => '\d{4}',
1279
		'CZ' => '\d{3}[ ]?\d{2}',
1280
		'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',
1281
		'DK' => '^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$',
1282
		'DO' => '\d{5}',
1283
		'DZ' => '\d{5}',
1284
		'EC' => '([A-Z]\d{4}[A-Z]|(?:[A-Z]{2})?\d{6})?',
1285
		'EE' => '\d{5}',
1286
		'EG' => '\d{5}',
1287
		'ES' => '^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$',
1288
		'ET' => '\d{4}',
1289
		'FI' => '\d{5}',
1290
		'FK' => 'FIQQ 1ZZ',
1291
		'FM' => '(9694[1-4])([ \-]\d{4})?',
1292
		'FO' => '\d{3}',
1293
		'FR' => '^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$',
1294
		'GE' => '\d{4}',
1295
		'GF' => '9[78]3\d{2}',
1296
		'GL' => '39\d{2}',
1297
		'GN' => '\d{3}',
1298
		'GP' => '9[78][01]\d{2}',
1299
		'GR' => '\d{3}[ ]?\d{2}',
1300
		'GS' => 'SIQQ 1ZZ',
1301
		'GT' => '\d{5}',
1302
		'GU' => '969[123]\d([ \-]\d{4})?',
1303
		'GW' => '\d{4}',
1304
		'HM' => '\d{4}',
1305
		'HN' => '(?:\d{5})?',
1306
		'HR' => '\d{5}',
1307
		'HT' => '\d{4}',
1308
		'HU' => '\d{4}',
1309
		'ID' => '\d{5}',
1310
		'IE' => '((D|DUBLIN)?([1-9]|6[wW]|1[0-8]|2[024]))?',
1311
		'IL' => '\d{5}',
1312
		'IN' => '^[1-9][0-9][0-9][0-9][0-9][0-9]$', // India.
1313
		'IO' => 'BBND 1ZZ',
1314
		'IQ' => '\d{5}',
1315
		'IS' => '\d{3}',
1316
		'IT' => '^(V-|I-)?[0-9]{5}$',
1317
		'JO' => '\d{5}',
1318
		'JP' => '\d{3}-\d{4}',
1319
		'KE' => '\d{5}',
1320
		'KG' => '\d{6}',
1321
		'KH' => '\d{5}',
1322
		'KR' => '\d{3}[\-]\d{3}',
1323
		'KW' => '\d{5}',
1324
		'KZ' => '\d{6}',
1325
		'LA' => '\d{5}',
1326
		'LB' => '(\d{4}([ ]?\d{4})?)?',
1327
		'LI' => '(948[5-9])|(949[0-7])',
1328
		'LK' => '\d{5}',
1329
		'LR' => '\d{4}',
1330
		'LS' => '\d{3}',
1331
		'LT' => '\d{5}',
1332
		'LU' => '\d{4}',
1333
		'LV' => '\d{4}',
1334
		'MA' => '\d{5}',
1335
		'MC' => '980\d{2}',
1336
		'MD' => '\d{4}',
1337
		'ME' => '8\d{4}',
1338
		'MG' => '\d{3}',
1339
		'MH' => '969[67]\d([ \-]\d{4})?',
1340
		'MK' => '\d{4}',
1341
		'MN' => '\d{6}',
1342
		'MP' => '9695[012]([ \-]\d{4})?',
1343
		'MQ' => '9[78]2\d{2}',
1344
		'MT' => '[A-Z]{3}[ ]?\d{2,4}',
1345
		'MU' => '(\d{3}[A-Z]{2}\d{3})?',
1346
		'MV' => '\d{5}',
1347
		'MX' => '\d{5}',
1348
		'MY' => '\d{5}',
1349
		'NC' => '988\d{2}',
1350
		'NE' => '\d{4}',
1351
		'NF' => '2899',
1352
		'NG' => '(\d{6})?',
1353
		'NI' => '((\d{4}-)?\d{3}-\d{3}(-\d{1})?)?',
1354
		'NL' => '^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$',
1355
		'NO' => '\d{4}',
1356
		'NP' => '\d{5}',
1357
		'NZ' => '\d{4}',
1358
		'OM' => '(PC )?\d{3}',
1359
		'PF' => '987\d{2}',
1360
		'PG' => '\d{3}',
1361
		'PH' => '\d{4}',
1362
		'PK' => '\d{5}',
1363
		'PL' => '\d{2}-\d{3}',
1364
		'PM' => '9[78]5\d{2}',
1365
		'PN' => 'PCRN 1ZZ',
1366
		'PR' => '00[679]\d{2}([ \-]\d{4})?',
1367
		'PT' => '\d{4}([\-]\d{3})?',
1368
		'PW' => '96940',
1369
		'PY' => '\d{4}',
1370
		'RE' => '9[78]4\d{2}',
1371
		'RO' => '\d{6}',
1372
		'RS' => '\d{5}',
1373
		'RU' => '\d{6}',
1374
		'SA' => '\d{5}',
1375
		'SE' => '^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$',
1376
		'SG' => '\d{6}',
1377
		'SH' => '(ASCN|STHL) 1ZZ',
1378
		'SI' => '\d{4}',
1379
		'SJ' => '\d{4}',
1380
		'SK' => '\d{3}[ ]?\d{2}',
1381
		'SM' => '4789\d',
1382
		'SN' => '\d{5}',
1383
		'SO' => '\d{5}',
1384
		'SZ' => '[HLMS]\d{3}',
1385
		'TC' => 'TKCA 1ZZ',
1386
		'TH' => '\d{5}',
1387
		'TJ' => '\d{6}',
1388
		'TM' => '\d{6}',
1389
		'TN' => '\d{4}',
1390
		'TR' => '\d{5}',
1391
		'TW' => '\d{3}(\d{2})?',
1392
		'UA' => '\d{5}',
1393
		'UK' => '^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$',
1394
		'US' => '^\d{5}([\-]?\d{4})?$',
1395
		'UY' => '\d{5}',
1396
		'UZ' => '\d{6}',
1397
		'VA' => '00120',
1398
		'VE' => '\d{4}',
1399
		'VI' => '008(([0-4]\d)|(5[01]))([ \-]\d{4})?',
1400
		'WF' => '986\d{2}',
1401
		'YT' => '976\d{2}',
1402
		'YU' => '\d{5}',
1403
		'ZA' => '\d{4}',
1404
		'ZM' => '\d{5}',
1405
	);
1406
1407
	if ( ! isset( $zip_regex[ $country_code ] ) || preg_match( '/' . $zip_regex[ $country_code ] . '/i', $zip ) ) {
1408
		$ret = true;
1409
	}
1410
1411
	return apply_filters( 'give_is_zip_valid', $ret, $zip, $country_code );
1412
}
1413
1414
/**
1415
 * Validate donation amount and auto set correct donation level id on basis of amount.
1416
 *
1417
 * 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.
1418
 *
1419
 * @param array $valid_data List of Valid Data.
1420
 *
1421
 * @return bool
1422
 */
1423
function give_validate_donation_amount( $valid_data ) {
0 ignored issues
show
Unused Code introduced by
The parameter $valid_data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1424
1425
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
1426
1427
	/* @var Give_Donate_Form $form */
1428
	$form = new Give_Donate_Form( $post_data['give-form-id'] );
1429
1430
	// Get the form currency.
1431
	$form_currency = give_get_currency( $post_data['give-form-id'] );
1432
1433
	$donation_level_matched = false;
1434
1435
	if ( $form->is_set_type_donation_form() ) {
1436
1437
		// Sanitize donation amount.
1438
		$post_data['give-amount'] = give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => $form_currency ) );
1439
1440
		// Backward compatibility.
1441
		if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1442
			$post_data['give-price-id'] = 'custom';
1443
		}
1444
1445
		$donation_level_matched = true;
1446
1447
	} elseif ( $form->is_multi_type_donation_form() ) {
1448
1449
		$variable_prices = $form->get_prices();
1450
1451
		// Bailout.
1452
		if ( ! $variable_prices ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $variable_prices of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1453
			return false;
1454
		}
1455
1456
		// Sanitize donation amount.
1457
		$post_data['give-amount']     = give_maybe_sanitize_amount( $post_data['give-amount'], array( 'currency' => $form_currency ) );
1458
		$variable_price_option_amount = give_maybe_sanitize_amount( give_get_price_option_amount( $post_data['give-form-id'], $post_data['give-price-id'] ), array( 'currency' => $form_currency ) );
1459
		$new_price_id                 = '';
1460
1461
		if ( $post_data['give-amount'] === $variable_price_option_amount ) {
1462
			return true;
1463
		}
1464
1465
		if ( $form->is_custom_price( $post_data['give-amount'] ) ) {
1466
			$new_price_id = 'custom';
1467
		} else {
1468
1469
			// Find correct donation level from all donation levels.
1470
			foreach ( $variable_prices as $variable_price ) {
1471
1472
				// Sanitize level amount.
1473
				$variable_price['_give_amount'] = give_maybe_sanitize_amount( $variable_price['_give_amount'] );
1474
1475
				// Set first match donation level ID.
1476
				if ( $post_data['give-amount'] === $variable_price['_give_amount'] ) {
1477
					$new_price_id = $variable_price['_give_id']['level_id'];
1478
					break;
1479
				}
1480
			}
1481
		}
1482
1483
		// If donation amount is not find in donation levels then check if form has custom donation feature enable or not.
1484
		// If yes then set price id to custom if amount is greater then custom minimum amount (if any).
1485
		if ( $post_data['give-price-id'] === $new_price_id ) {
1486
			$donation_level_matched = true;
1487
		}
1488
	} // End if().
1489
1490
	if ( ! $donation_level_matched ) {
1491
		give_set_error(
1492
			'invalid_donation_amount',
1493
			sprintf(
1494
			/* translators: %s: invalid donation amount */
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 16 spaces, but found 12.
Loading history...
1495
				__( 'Donation amount %s is invalid.', 'give' ),
1496
				give_currency_filter(
1497
					give_format_amount( $post_data['give-amount'], array( 'sanitize' => false, ) )
1498
				)
1499
			)
1500
		);
1501
	}
1502
}
1503
1504
add_action( 'give_checkout_error_checks', 'give_validate_donation_amount', 10, 1 );
1505
1506
/**
1507
 * Validate Required Form Fields.
1508
 *
1509
 * @param int $form_id Form ID.
1510
 *
1511
 * @since 2.0
1512
 */
1513
function give_validate_required_form_fields( $form_id ) {
1514
1515
	// Sanitize values submitted with donation form.
1516
	$post_data = give_clean( $_POST ); // WPCS: input var ok, sanitization ok, CSRF ok.
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
1517
1518
	// Loop through required fields and show error messages.
1519
	foreach ( give_get_required_fields( $form_id ) as $field_name => $value ) {
1520
1521
		// Clean Up Data of the input fields.
1522
		$field_value = $post_data[ $field_name ];
1523
1524
		// Check whether the required field is empty, then show the error message.
1525
		if ( in_array( $value, give_get_required_fields( $form_id ), true ) && empty( $field_value ) ) {
1526
			give_set_error( $value['error_id'], $value['error_message'] );
1527
		}
1528
	}
1529
}
1530
1531
/**
1532
 * Validates and checks if name fields are valid or not.
1533
 *
1534
 * @param array $post_data List of post data.
1535
 *
1536
 * @since 2.1
1537
 *
1538
 * @return void
1539
 */
1540
function give_donation_form_validate_name_fields( $post_data ) {
1541
1542
	$is_alpha_first_name = ( ! is_email( $post_data['give_first'] ) && ! preg_match( '~[0-9]~', $post_data['give_first'] ) );
1543
	$is_alpha_last_name  = ( ! is_email( $post_data['give_last'] ) && ! preg_match( '~[0-9]~', $post_data['give_last'] ) );
1544
1545
	if ( ! $is_alpha_first_name || ( ! empty( $post_data['give_last'] ) && ! $is_alpha_last_name ) ) {
1546
		give_set_error( 'invalid_name', esc_html__( 'The First Name and Last Name fields cannot contain an email address or numbers.', 'give' ) );
1547
	}
1548
}
1549