Issues (1282)

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