Issues (4335)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/formatting.php (15 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Formatting functions for taking care of proper number formats and such
4
 *
5
 * @package     Give
6
 * @subpackage  Functions/Formatting
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
 * Get Currency Formatting Settings for each donation.
19
 *
20
 * @param int|string $id_or_currency_code Donation ID or Currency code.
21
 *
22
 * @since 1.8.15
23
 *
24
 * @return mixed
25
 */
26
function give_get_currency_formatting_settings( $id_or_currency_code = null ) {
27
	$give_options = give_get_settings();
28
	$setting      = array();
29
30
	if ( ! empty( $id_or_currency_code ) ) {
31
		$currencies = give_get_currencies( 'all' );
32
33
		// Set default formatting setting only if currency not set as global currency.
34
		if (
35
			is_string( $id_or_currency_code ) &&
36
			! empty( $give_options['currency'] ) &&
37
			$id_or_currency_code !== $give_options['currency'] &&
38
			array_key_exists( $id_or_currency_code, $currencies )
39
		) {
40
			$setting = $currencies[ $id_or_currency_code ]['setting'];
41
		} elseif ( is_numeric( $id_or_currency_code ) && 'give_payment' === get_post_type( $id_or_currency_code ) ) {
42
			$currency = give_get_meta( $id_or_currency_code, '_give_payment_currency', true );
43
44
			if (
45
				! empty( $currency) &&
0 ignored issues
show
Expected 1 spaces before closing bracket; 0 found
Loading history...
46
				$give_options['currency'] !== $currency
47
			) {
48
				$setting = $currencies[ $currency ]['setting'];
49
			}
50
		}
51
	}
52
53
	if ( empty( $setting ) ) {
54
		// Set thousand separator.
55
		$thousand_separator = isset( $give_options['thousands_separator'] ) ? $give_options['thousands_separator'] : ',';
56
		$thousand_separator = empty( $thousand_separator ) ? ' ' : $thousand_separator;
57
58
		// Set decimal separator.
59
		$default_decimal_separators = array(
60
			'.' => ',',
61
			',' => '.',
62
		);
63
64
		$default_decimal_separator = in_array( $thousand_separator, $default_decimal_separators ) ?
65
			$default_decimal_separators[ $thousand_separator ] :
66
			'.';
67
68
		$decimal_separator = ! empty( $give_options['decimal_separator'] ) ? $give_options['decimal_separator'] : $default_decimal_separator;
69
70
		$setting = array(
71
			'currency_position'   => give_get_option( 'currency_position', 'before' ),
72
			'thousands_separator' => $thousand_separator,
73
			'decimal_separator'   => $decimal_separator,
74
			'number_decimals'     => give_get_option( 'number_decimals', 0 ),
75
		);
76
	}
77
78
	/**
79
	 * Filter the currency formatting setting.
80
	 *
81
	 * @since 1.8.15
82
	 */
83
	return apply_filters( 'give_get_currency_formatting_settings', $setting, $id_or_currency_code );
84
}
85
86
/**
87
 * Get decimal count
88
 *
89
 * @since 1.6
90
 *
91
 * @param int|string $id_or_currency_code
92
 *
93
 * @return mixed
94
 */
95 View Code Duplication
function give_get_price_decimals( $id_or_currency_code = null ) {
0 ignored issues
show
This function seems to be duplicated in 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...
96
	// Set currency on basis of donation id.
97
	if ( empty( $id_or_currency_code ) ) {
98
		$id_or_currency_code = give_get_currency();
99
	}
100
101
	$number_of_decimals = 0;
102
103
	if ( ! give_is_zero_based_currency( $id_or_currency_code ) ) {
104
		$setting            = give_get_currency_formatting_settings( $id_or_currency_code );
105
		$number_of_decimals = $setting['number_decimals'];
106
	}
107
108
	/**
109
	 * Filter the number of decimals
110
	 *
111
	 * @since 1.6
112
	 */
113
	return apply_filters( 'give_sanitize_amount_decimals', $number_of_decimals, $id_or_currency_code );
114
}
115
116
/**
117
 * Get thousand separator
118
 *
119
 * @param int|string $id_or_currency_code
120
 *
121
 * @since 1.6
122
 *
123
 * @return mixed
124
 */
125
function give_get_price_thousand_separator( $id_or_currency_code = null ) {
126
	$setting = give_get_currency_formatting_settings( $id_or_currency_code );
127
128
	/**
129
	 * Filter the thousand separator
130
	 *
131
	 * @since 1.6
132
	 */
133
	return apply_filters( 'give_get_price_thousand_separator', $setting['thousands_separator'], $id_or_currency_code );
134
}
135
136
/**
137
 * Get decimal separator
138
 *
139
 * @param string $id_or_currency_code
140
 *
141
 * @since 1.6
142
 *
143
 * @return mixed
144
 */
145
function give_get_price_decimal_separator( $id_or_currency_code = null ) {
146
	$setting = give_get_currency_formatting_settings( $id_or_currency_code );
147
148
	/**
149
	 * Filter the thousand separator
150
	 *
151
	 * @since 1.6
152
	 */
153
	return apply_filters( 'give_get_price_decimal_separator', $setting['decimal_separator'], $id_or_currency_code );
154
}
155
156
/**
157
 * Sanitize Amount before saving to database
158
 *
159
 * @since      1.8.12
160
 *
161
 * @param  int|float|string $number Expects either a float or a string with a decimal separator only (no thousands)
162
 * @param  array|bool       $args   It accepts 'number_decimals', 'trim_zeros', 'currency'.
163
 *
164
 * @return string $amount Newly sanitized amount
165
 */
166
function give_sanitize_amount_for_db( $number, $args = array() ) {
167
	$args['number_decimals'] = 6;
168
169
	if (
170
		( isset( $args['currency'] ) && 'BTC' === $args['currency'] )
171
		|| 'BTC' === give_get_currency()
172
	) {
173
		$args['number_decimals'] = 10;
174
	}
175
176
	return give_maybe_sanitize_amount( $number, $args );
177
}
178
179
/**
180
 * Sanitize Amount before saving to database
181
 *
182
 * @since      1.8.12
183
 *
184
 * @param  int|float|string $number Expects either a float or a string with a decimal separator only (no thousands)
185
 * @param  array|bool       $args   It accepts 'number_decimals', 'trim_zeros', 'currency'.
186
 *
187
 * @return string $amount Newly sanitized amount
188
 */
189
function give_maybe_sanitize_amount( $number, $args = array() ) {
190
	// Bailout.
191
	if ( empty( $number ) || ( ! is_numeric( $number ) && ! is_string( $number ) ) ) {
192
		return $number;
193
	}
194
195
	$func_args = func_get_args();
196
197
	// Backward compatibility.
198 View Code Duplication
	if ( isset( $func_args[1] ) && ( is_bool( $func_args[1] ) || is_numeric( $func_args[1] ) ) ) {
0 ignored issues
show
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...
199
		$args = array(
200
			'number_decimals' => $func_args[1],
201
			'trim_zeros'      => isset( $func_args[2] ) ? $func_args[2] : false,
202
		);
203
	}
204
205
	$args = wp_parse_args(
206
		$args,
207
		array(
208
			'number_decimals' => false,
209
			'trim_zeros'      => false,
210
			'currency'        => give_get_currency(),
211
		)
212
	);
213
214
	$thousand_separator = give_get_price_thousand_separator( $args['currency'] );
215
	$decimal_separator  = give_get_price_decimal_separator( $args['currency'] );
216
	$number_decimals    = is_bool( $args['number_decimals'] ) ?
217
		give_get_price_decimals( $args['currency'] ) :
218
		$args['number_decimals'];
219
220
	// Explode number by . decimal separator.
221
	$number_parts = explode( '.', $number );
222
223
	// Remove currency symbols from number if any.
224
	$number = trim( str_replace( give_currency_symbols( true ), '', $number ) );
225
226
	if (
227
		// Non formatted number.
228
		false === strpos( $number, $thousand_separator )
229
		&& false === strpos( $number, $decimal_separator )
230
	) {
231
		return number_format( $number, $number_decimals, '.', '' );
232
	} elseif (
233
		// Decimal formatted number.
234
		// If number of decimal place set to non zero and
235
		// number only contains `.` as separator, precision set to less then or equal to number of decimal
236
		// then number will be consider as decimal formatted which means number is already sanitized.
237
		$number_decimals
238
		&& '.' === $thousand_separator
239
		&& false !== strpos( $number, $thousand_separator )
240
		&& false === strpos( $number, $decimal_separator )
241
		&& 2 === count( $number_parts )
242
		&& ( $number_decimals >= strlen( $number_parts[1] ) )
243
	) {
244
		return number_format( $number, $number_decimals, '.', '' );
245
	}
246
247
	// Handle thousand separator as '.'
248
	// Handle sanitize database values.
249
	$is_db_sanitize_val = ( 2 === count( $number_parts ) &&
250
	                        is_numeric( $number_parts[0] ) &&
251
	                        is_numeric( $number_parts[1] ) &&
252
	                        ( in_array( strlen( $number_parts[1] ), array( 6, 10 ) ) ) );
253
254
	if ( $is_db_sanitize_val ) {
255
		// Sanitize database value.
256
		return number_format( $number, $number_decimals, '.', '' );
257
258
	} elseif (
259
		'.' === $thousand_separator &&
260
		false !== strpos( $number, $thousand_separator )
261
	) {
262
		// Fix point thousand separator value.
263
		$number = str_replace( '.', '', $number );
264
	}
265
266
	return give_sanitize_amount( $number, $args );
267
}
268
269
/**
270
 * Sanitize Amount
271
 *
272
 * Note: Do not this function to sanitize amount instead use give_maybe_sanitize_amount function.
273
 *
274
 * Returns a sanitized amount by stripping out thousands separators.
275
 *
276
 * @since      1.0
277
 *
278
 * @param  int|float|string $number Expects either a float or a string with a decimal separator only (no thousands)
279
 * @param  array|bool       $args   It accepts 'number_decimals', 'trim_zeros', 'currency'.
280
 *
281
 * @return string $amount Newly sanitized amount
282
 */
283
function give_sanitize_amount( $number, $args = array() ) {
284
285
	// Bailout.
286
	if ( empty( $number ) || ( ! is_numeric( $number ) && ! is_string( $number ) ) ) {
287
		return $number;
288
	}
289
290
	// Get function arguments.
291
	$func_args = func_get_args();
292
293
	// Backward compatibility.
294 View Code Duplication
	if ( isset( $func_args[1] ) && ( is_bool( $func_args[1] ) || is_numeric( $func_args[1] ) ) ) {
0 ignored issues
show
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...
295
		$args = array(
296
			'number_decimals' => $func_args[1],
297
			'trim_zeros'      => isset( $func_args[2] ) ? $func_args[2] : false,
298
		);
299
	}
300
301
	$args = wp_parse_args(
302
		$args,
303
		array(
304
			'number_decimals' => false,
305
			'trim_zeros'      => false,
306
			'currency'        => give_get_currency(),
307
		)
308
	);
309
310
	// Remove slash from amount.
311
	// If thousand or decimal separator is set to ' then in $_POST or $_GET param we will get an escaped number.
312
	// To prevent notices and warning remove slash from amount/number.
313
	$number = wp_unslash( $number );
314
315
	$thousand_separator = give_get_price_thousand_separator( $args['currency'] );
316
317
	$locale   = localeconv();
318
	$decimals = array(
319
		give_get_price_decimal_separator( $args['currency'] ),
320
		$locale['decimal_point'],
321
		$locale['mon_decimal_point'],
322
	);
323
324
	// Remove locale from string
325
	if ( ! is_float( $number ) ) {
326
		$number = str_replace( $decimals, '.', $number );
327
	}
328
329
	// Remove thousand amount formatting if amount has.
330
	// This condition use to add backward compatibility to version before 1.6, because before version 1.6 we were saving formatted amount to db.
331
	// Do not replace thousand separator from price if it is same as decimal separator, because it will be already replace by above code.
332
	if ( ! in_array( $thousand_separator, $decimals ) && ( false !== strpos( $number, $thousand_separator ) ) ) {
333
		$number = str_replace( $thousand_separator, '', $number );
334
	} elseif ( in_array( $thousand_separator, $decimals ) ) {
335
		$number = preg_replace( '/\.(?=.*\.)/', '', $number );
336
	}
337
338
	// Remove non numeric entity before decimal separator.
339
	$number     = preg_replace( '/[^0-9\.]/', '', $number );
340
	$default_dp = give_get_price_decimals( $args['currency'] );
341
342
	// Reset negative amount to zero.
343
	if ( 0 > $number ) {
344
		$number = number_format( 0, $default_dp, '.' );
345
	}
346
347
	// If number does not have decimal then add number of decimals to it.
348
	if (
349
		false === strpos( $number, '.' )
350
		|| ( $default_dp > strlen( substr( $number, strpos( $number, '.' ) + 1 ) ) )
351
	) {
352
		$number = number_format( $number, $default_dp, '.', '' );
353
	}
354
355
	// Format number by custom number of decimals.
356
	if ( false !== $args['number_decimals'] ) {
357
		$dp     = intval( is_bool( $args['number_decimals'] ) ? $default_dp : $args['number_decimals'] );
358
		$dp     = apply_filters( 'give_sanitize_amount_decimals', $dp, $number );
359
		$number = number_format( floatval( $number ), $dp, '.', '' );
360
	}
361
362
	// Trim zeros.
363
	if ( $args['trim_zeros'] && strstr( $number, '.' ) ) {
364
		$number = rtrim( rtrim( $number, '0' ), '.' );
365
	}
366
367
	/**
368
	 * Filter the sanitize amount
369
	 *
370
	 * @since 1.0
371
	 */
372
	return apply_filters( 'give_sanitize_amount', $number );
373
}
374
375
/**
376
 * Returns a nicely formatted amount.
377
 *
378
 * @since 1.0
379
 *
380
 * @param string $amount Price amount to format
381
 * @param array  $args   Array of arguments.
382
 *
383
 * @return string $amount   Newly formatted amount or Price Not Available
384
 */
385
function give_format_amount( $amount, $args = array() ) {
386
	// Backward compatibility.
387
	if ( is_bool( $args ) ) {
388
		$args = array(
389
			'decimal' => $args,
390
		);
391
	}
392
393
	$default_args = array(
394
		'decimal'     => true,
395
		'sanitize'    => true,
396
		'donation_id' => 0,
397
		'currency'    => '',
398
	);
399
400
	$args = wp_parse_args( $args, $default_args );
401
402
	// Set Currency based on donation id, if required.
403
	if ( $args['donation_id'] && empty( $args['currency'] ) ) {
404
		$args['currency'] = give_get_meta( $args['donation_id'], '_give_payment_currency', true );
405
	}
406
407
	$formatted     = 0;
408
	$currency      = ! empty( $args['currency'] ) ? $args['currency'] : give_get_currency( $args['donation_id'] );
409
	$thousands_sep = give_get_price_thousand_separator( $currency );
410
	$decimal_sep   = give_get_price_decimal_separator( $currency );
411
	$decimals      = ! empty( $args['decimal'] ) ? give_get_price_decimals( $currency ) : 0;
412
413
	if ( ! empty( $amount ) ) {
414
		// Sanitize amount before formatting.
415
		$amount = ! empty( $args['sanitize'] ) ?
416
			give_maybe_sanitize_amount( $amount, array( 'number_decimals' => $decimals, 'currency' => $currency ) ) :
417
			number_format( $amount, $decimals, '.', '' );
418
419
		switch ( $currency ) {
420
			case 'INR':
421
				$decimal_amount = '';
422
423
				// Extract decimals from amount
424
				if ( ( $pos = strpos( $amount, '.' ) ) !== false ) {
0 ignored issues
show
Found "!== false". Use Yoda Condition checks, you must
Loading history...
425
					if ( ! empty( $decimals ) ) {
426
						$decimal_amount = substr( round( substr( $amount, $pos ), $decimals ), 1 );
427
						$amount         = substr( $amount, 0, $pos );
428
429
						if ( ! $decimal_amount ) {
430
							$decimal_amount = substr( "{$decimal_sep}0000000000", 0, ( $decimals + 1 ) );
431
						} elseif ( ( $decimals + 1 ) > strlen( $decimal_amount ) ) {
432
							$decimal_amount = substr( "{$decimal_amount}000000000", 0, ( $decimals + 1 ) );
433
						}
434
					} else {
435
						$amount = number_format( $amount, $decimals, $decimal_sep, '' );
436
					}
437
				}
438
439
				// Extract last 3 from amount
440
				$result = substr( $amount, - 3 );
441
				$amount = substr( $amount, 0, - 3 );
442
443
				// Apply digits 2 by 2
444
				while ( strlen( $amount ) > 0 ) {
445
					$result = substr( $amount, - 2 ) . $thousands_sep . $result;
446
					$amount = substr( $amount, 0, - 2 );
447
				}
448
449
				$formatted = $result . $decimal_amount;
450
				break;
451
452
			default:
453
				$formatted = number_format( $amount, $decimals, $decimal_sep, $thousands_sep );
454
		}
455
	}
456
457
	/**
458
	 * Filter the formatted amount
459
	 *
460
	 * @since 1.0
461
	 */
462
	return apply_filters( 'give_format_amount', $formatted, $amount, $decimals, $decimal_sep, $thousands_sep, $currency, $args );
463
}
464
465
466
/**
467
 * Get human readable amount.
468
 *
469
 * Note: This function only support large number formatting from million to trillion
470
 *
471
 * @since 1.6
472
 *
473
 * @use   give_get_price_thousand_separator Get thousand separator.
474
 *
475
 * @param string $amount formatted amount number.
476
 * @param array  $args   Array of arguments.
477
 *
478
 * @return string  formatted amount number with large number names.
479
 */
480
function give_human_format_large_amount( $amount, $args = array() ) {
481
	// Sanitize amount.
482
	$sanitize_amount = give_maybe_sanitize_amount( $amount );
483
484
	// Bailout.
485
	if ( ! floatval( $sanitize_amount ) ) {
486
		return '0';
487
	};
488
489
	// Set default currency;
490
	if ( empty( $args['currency'] ) ) {
491
		$args['currency'] = give_get_currency();
492
	}
493
494
	// Get thousand separator.
495
	$thousands_sep = give_get_price_thousand_separator();
496
497
	// Explode amount to calculate name of large numbers.
498
	$amount_array = explode( $thousands_sep, $amount );
499
500
	// Calculate amount parts count.
501
	$amount_count_parts = count( $amount_array );
502
503
	// Human format amount (default).
504
	$human_format_amount = $amount;
505
506
	switch ( $args['currency'] ) {
507 View Code Duplication
		case 'INR':
0 ignored issues
show
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...
508
			// Calculate large number formatted amount.
509
			if ( 4 < $amount_count_parts ) {
510
				$human_format_amount = sprintf( esc_html__( '%s arab', 'give' ), round( ( $sanitize_amount / 1000000000 ), 2 ) );
511
			} elseif ( 3 < $amount_count_parts ) {
512
				$human_format_amount = sprintf( esc_html__( '%s crore', 'give' ), round( ( $sanitize_amount / 10000000 ), 2 ) );
513
			} elseif ( 2 < $amount_count_parts ) {
514
				$human_format_amount = sprintf( esc_html__( '%s lakh', 'give' ), round( ( $sanitize_amount / 100000 ), 2 ) );
515
			}
516
			break;
517 View Code Duplication
		default:
0 ignored issues
show
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...
518
			// Calculate large number formatted amount.
519
			if ( 4 < $amount_count_parts ) {
520
				$human_format_amount = sprintf( esc_html__( '%s trillion', 'give' ), round( ( $sanitize_amount / 1000000000000 ), 2 ) );
521
			} elseif ( 3 < $amount_count_parts ) {
522
				$human_format_amount = sprintf( esc_html__( '%s billion', 'give' ), round( ( $sanitize_amount / 1000000000 ), 2 ) );
523
			} elseif ( 2 < $amount_count_parts ) {
524
				$human_format_amount = sprintf( esc_html__( '%s million', 'give' ), round( ( $sanitize_amount / 1000000 ), 2 ) );
525
			}
526
	}
527
528
	return apply_filters( 'give_human_format_large_amount', $human_format_amount, $amount, $sanitize_amount );
529
}
530
531
/**
532
 * Returns a nicely formatted amount with custom decimal separator.
533
 *
534
 * @since 1.0
535
 *
536
 * @param array           $args        {
537
 *
538
 * @type int|float|string $amount      Formatted or sanitized price. (optional if donation id set)
539
 * @type int              $donation_id donation amount (optional if set amount, but provide it for better result if formatting decimal amount of donation).
540
 * @type string           $currency    donation amount (optional if set donation id). Provide either amount or donation id
541
 * @type int|bool         $dp          number of decimals
542
 * @type bool             $sanitize    Whether or not sanitize number
543
 * }
544
 *
545
 * @return string $amount Newly formatted amount or Price Not Available
546
 */
547
function give_format_decimal( $args ) {
548
	// Backward compatibility.
549
	if ( ! is_array( $args ) ) {
550
		$func_args = func_get_args();
551
		$args      = array(
552
			'amount'   => $func_args[0],
553
			'dp'       => isset( $func_args[1] ) ? $func_args[1] : false,
554
			'sanitize' => isset( $func_args[2] ) ? $func_args[2] : true,
555
		);
556
	}
557
558
	$args = wp_parse_args(
559
		$args,
560
		array(
561
			'amount'      => '',
562
			'donation_id' => 0,
563
			'currency'    => '',
564
			'dp'          => false,
565
			'sanitize'    => false,
566
		)
567
	);
568
569
	if( ! empty( $args['donation_id'] ) ) {
0 ignored issues
show
Space after opening control structure is required
Loading history...
No space before opening parenthesis is prohibited
Loading history...
570
571
		// Set currency if not already done.
572
		if( empty( $args['currency'] ) ) {
0 ignored issues
show
Space after opening control structure is required
Loading history...
No space before opening parenthesis is prohibited
Loading history...
573
			$args['currency'] = give_get_payment_currency_code( $args['donation_id'] );
574
		}
575
576
		// Set amount if not already done.
577
		if( empty( $args['amount'] ) ) {
0 ignored issues
show
Space after opening control structure is required
Loading history...
No space before opening parenthesis is prohibited
Loading history...
578
			$args['amount'] = give_donation_amount( $args['donation_id'] );
579
		}
580
	}
581
582
	$decimal_separator = give_get_price_decimal_separator();
583
	$formatted_amount  = $args['sanitize'] ?
584
		give_maybe_sanitize_amount( $args['amount'], array( 'number_decimals' => $args['dp'], 'currency' => $args['currency'] ) ) :
585
		number_format( $args['amount'], ( is_bool( $args['dp'] ) ? give_get_price_decimals( $args['currency'] ) : $args['dp'] ), '.', '' );
586
587
	if ( false !== strpos( $formatted_amount, '.' ) ) {
588
		$formatted_amount = str_replace( '.', $decimal_separator, $formatted_amount );
589
	}
590
591
	return apply_filters( 'give_format_decimal', $formatted_amount, $args['amount'], $decimal_separator, $args );
592
}
593
594
/**
595
 * Get date format string on basis of given context.
596
 *
597
 * @since 1.7
598
 *
599
 * @param  string $date_context Date format context name.
600
 *
601
 * @return string                  Date format string
602
 */
603
function give_date_format( $date_context = '' ) {
604
	/**
605
	 * Filter the date context
606
	 *
607
	 * You can add your own date context or use already exist context.
608
	 * For example:
609
	 *    add_filter( 'give_date_format_contexts', 'add_new_date_contexts' );
610
	 *    function add_new_date_contexts( $date_format_contexts ) {
611
	 *        // You can add single context like this $date_format_contexts['checkout'] = 'F j, Y';
612
	 *        // Instead add multiple date context at once.
613
	 *        $new_date_format_contexts = array(
614
	 *            'checkout' => 'F j, Y',
615
	 *            'report'   => 'Y-m-d',
616
	 *            'email'    => 'm/d/Y',
617
	 *        );
618
	 *
619
	 *       // Merge date contexts array only if you are adding multiple date contexts at once otherwise return  $date_format_contexts.
620
	 *       return array_merge( $new_date_format_contexts, $date_format_contexts );
621
	 *
622
	 *    }
623
	 */
624
	$date_format_contexts = apply_filters( 'give_date_format_contexts', array() );
625
626
	// Set date format to default date format.
627
	$date_format = get_option( 'date_format' );
628
629
	// Update date format if we have non empty date format context array and non empty date format string for that context.
630
	if ( $date_context && ! empty( $date_format_contexts ) && array_key_exists( $date_context, $date_format_contexts ) ) {
631
		$date_format = ! empty( $date_format_contexts[ $date_context ] )
632
			? $date_format_contexts[ $date_context ]
633
			: $date_format;
634
	}
635
636
	return apply_filters( 'give_date_format', $date_format );
637
}
638
639
/**
640
 * Get cache key.
641
 *
642
 * @since      1.7
643
 * @deprecated 1.8.7 You can access this function from Give_Cache.
644
 *
645
 * @param  string $action     Cache key prefix.
646
 * @param array  $query_args Query array.
647
 *
648
 * @return string
649
 */
650
function give_get_cache_key( $action, $query_args ) {
651
	return Give_Cache::get_key( $action, $query_args );
652
}
653
654
/**
655
 * Clean variables using sanitize_text_field. Arrays are cleaned recursively.
656
 * Non-scalar values are ignored.
657
 *
658
 * @since  1.8
659
 *
660
 * @param  string|array $var
661
 *
662
 * @return string|array
663
 */
664
function give_clean( $var ) {
665
	if ( is_array( $var ) ) {
666
		return array_map( 'give_clean', $var );
667
	} else {
668
		return is_scalar( $var ) ? sanitize_text_field( wp_unslash( $var ) ) : $var;
669
	}
670
}
671
672
/**
673
 * Transforms php.ini notation for numbers (like '2M') to an integer.
674
 *
675
 * @since 1.8
676
 *
677
 * @param $size
678
 *
679
 * @return int
680
 */
681
function give_let_to_num( $size ) {
682
	$l   = substr( $size, - 1 );
683
	$ret = substr( $size, 0, - 1 );
684
	switch ( strtoupper( $l ) ) {
685
		case 'P':
686
			$ret *= 1024;
687
		case 'T':
688
			$ret *= 1024;
689
		case 'G':
690
			$ret *= 1024;
691
		case 'M':
692
			$ret *= 1024;
693
		case 'K':
694
			$ret *= 1024;
695
	}
696
697
	return $ret;
698
}
699
700
/**
701
 * Verify nonce.
702
 *
703
 * @since 1.8
704
 *
705
 * @param string $nonce       Nonce Hash.
706
 * @param int    $action      Nonce verification action.
707
 * @param array  $wp_die_args Nonce fail arguments.
708
 *
709
 * @return bool
710
 */
711
function give_validate_nonce( $nonce, $action = - 1, $wp_die_args = array() ) {
712
713
	// Verify nonce.
714
	$verify_nonce = wp_verify_nonce( $nonce, $action );
715
716
	// On ajax request send nonce verification status.
717
	if ( wp_doing_ajax() ) {
718
		return $verify_nonce;
719
	}
720
721
	if ( ! $verify_nonce ) {
722
		$wp_die_args = wp_parse_args(
723
			$wp_die_args,
724
			array(
725
				'message' => __( 'Nonce verification has failed.', 'give' ),
726
				'title'   => __( 'Error', 'give' ),
727
				'args'    => array(
728
					'response' => 403,
729
				),
730
			)
731
		);
732
733
		wp_die(
734
			$wp_die_args['message'],
735
			$wp_die_args['title'],
736
			$wp_die_args['args']
737
		);
738
	}
739
740
	return true;
741
}
742
743
/**
744
 * Verify nonce while processing donation form.
745
 *
746
 * @since 2.0
747
 *
748
 * @param string $nonce   Nonce value.
749
 * @param int    $form_id Donation Form ID.
750
 *
751
 * @return bool
752
 */
753
function give_verify_donation_form_nonce( $nonce = '', $form_id ) {
754
755
	// Form nonce action.
756
	$nonce_action = "give_donation_form_nonce_{$form_id}";
757
758
	// Nonce validation.
759
	$verify_nonce = give_validate_nonce( $nonce, $nonce_action );
760
761
	if ( ! $verify_nonce ) {
762
		give_set_error( 'donation_form_nonce', __( 'Nonce verification has failed.', 'give' ) );
763
	}
764
765
	return $verify_nonce;
766
}
767
768
/**
769
 * Check variable and get default or valid value.
770
 *
771
 * Helper function to check if a variable is set, empty, etc.
772
 *
773
 * @since 1.8
774
 *
775
 * @param                   $variable
776
 * @param string (optional) $conditional    default value: isset
777
 * @param mixed (optional)  $default        default value: false
778
 * @param string (optional) $array_key_name default value: false
779
 *
780
 * @return mixed
781
 */
782
function give_check_variable( $variable, $conditional = '', $default = false, $array_key_name = '' ) {
783
	// Get value from array if array key non empty.
784
	if( empty( $array_key_name ) ) {
0 ignored issues
show
Space after opening control structure is required
Loading history...
No space before opening parenthesis is prohibited
Loading history...
785
		switch ( $conditional ) {
786
			case 'isset_empty':
787
				$variable = ( isset( $variable ) && ! empty( $variable ) ) ? $variable : $default;
788
				break;
789
790
			case 'empty':
791
				$variable = ! empty( $variable ) ? $variable : $default;
792
				break;
793
794
			case 'null':
795
				$variable = ! is_null( $variable ) ? $variable : $default;
796
				break;
797
798
			default:
799
				$variable = isset( $variable ) ? $variable : $default;
800
		}
801
	} else {
802
		$isset = array_key_exists( $array_key_name, $variable );
803
804
		switch ( $conditional ) {
805
			case 'isset_empty':
806
				$variable = ( $isset && ! empty( $variable[ $array_key_name ] ) ) ? $variable[ $array_key_name ] : $default;
807
				break;
808
809
			case 'empty':
810
				$variable = ! empty( $variable[ $array_key_name ] ) ? $variable[ $array_key_name ] : $default;
811
				break;
812
813
			case 'null':
814
				$variable = $isset && ! is_null( $variable[ $array_key_name ] ) ? $variable[ $array_key_name ] : $default;
815
				break;
816
817
			default:
818
				$variable = $isset && isset( $variable[ $array_key_name ] ) ? $variable[ $array_key_name ] : $default;
819
		}
820
	}
821
822
	return $variable;
823
824
}
825