Completed
Push — master ( b71328...08c185 )
by Brian
20s queued 15s
created

wpinv_get_currencies()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1
c 2
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Contains functions related to Invoicing plugin.
4
 *
5
 * @since 1.0.0
6
 * @package Invoicing
7
 */
8
9
// MUST have WordPress.
10
if ( !defined( 'WPINC' ) ) {
11
    exit( 'Do NOT access this file directly: ' . basename( __FILE__ ) );
12
}
13
14
function wpinv_item_quantities_enabled() {
15
    $ret = wpinv_get_option( 'item_quantities', true );
16
17
    return (bool) apply_filters( 'wpinv_item_quantities_enabled', $ret );
18
}
19
20
function wpinv_get_ip() {
21
    $ip = '127.0.0.1';
22
23
    if ( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
24
        $ip = sanitize_text_field( $_SERVER['HTTP_CLIENT_IP'] );
25
    } elseif ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
26
        $ip = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED_FOR'] );
27
    } elseif( !empty( $_SERVER['REMOTE_ADDR'] ) ) {
28
        $ip = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
29
    }
30
31
    return apply_filters( 'wpinv_get_ip', $ip );
32
}
33
34
function wpinv_get_user_agent() {
35
    if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
36
        $user_agent = sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] );
37
    } else {
38
        $user_agent = '';
39
    }
40
41
    return apply_filters( 'wpinv_get_user_agent', $user_agent );
42
}
43
44
function wpinv_sanitize_amount( $amount, $decimals = NULL ) {
45
    $is_negative   = false;
46
    $thousands_sep = wpinv_thousands_separator();
47
    $decimal_sep   = wpinv_decimal_separator();
48
    if ( $decimals === NULL ) {
49
        $decimals = wpinv_decimals();
50
    }
51
52
    // Sanitize the amount
53
    if ( $decimal_sep == ',' && false !== ( $found = strpos( $amount, $decimal_sep ) ) ) {
0 ignored issues
show
Unused Code introduced by
The assignment to $found is dead and can be removed.
Loading history...
54
        if ( ( $thousands_sep == '.' || $thousands_sep == ' ' ) && false !== ( $found = strpos( $amount, $thousands_sep ) ) ) {
55
            $amount = str_replace( $thousands_sep, '', $amount );
56
        } elseif( empty( $thousands_sep ) && false !== ( $found = strpos( $amount, '.' ) ) ) {
57
            $amount = str_replace( '.', '', $amount );
58
        }
59
60
        $amount = str_replace( $decimal_sep, '.', $amount );
61
    } elseif( $thousands_sep == ',' && false !== ( $found = strpos( $amount, $thousands_sep ) ) ) {
62
        $amount = str_replace( $thousands_sep, '', $amount );
63
    }
64
65
    if( $amount < 0 ) {
66
        $is_negative = true;
67
    }
68
69
    $amount   = preg_replace( '/[^0-9\.]/', '', $amount );
70
71
    $decimals = apply_filters( 'wpinv_sanitize_amount_decimals', absint( $decimals ), $amount );
72
    $amount   = number_format( (double) $amount, absint( $decimals ), '.', '' );
73
74
    if( $is_negative ) {
75
        $amount *= -1;
76
    }
77
78
    return apply_filters( 'wpinv_sanitize_amount', $amount, $decimals );
79
}
80
add_filter( 'wpinv_sanitize_amount_decimals', 'wpinv_currency_decimal_filter', 10, 1 );
81
82
function wpinv_round_amount( $amount, $decimals = NULL ) {
83
    if ( $decimals === NULL ) {
84
        $decimals = wpinv_decimals();
85
    }
86
    
87
    $amount = round( (double)$amount, wpinv_currency_decimal_filter( absint( $decimals ) ) );
88
89
    return apply_filters( 'wpinv_round_amount', $amount, $decimals );
90
}
91
92
/**
93
 * Get all invoice statuses.
94
 *
95
 * @since 1.0.19
96
 * @return array
97
 */
98
function wpinv_get_invoice_statuses( $draft = false, $trashed = false, $invoice = false ) {
99
	$invoice_statuses = array(
100
		'wpi-pending'    => _x( 'Pending payment', 'Invoice status', 'invoicing' ),
101
        'publish'        => _x( 'Paid', 'Invoice status', 'invoicing' ),
102
        'wpi-processing' => _x( 'Processing', 'Invoice status', 'invoicing' ),
103
		'wpi-onhold'     => _x( 'On hold', 'Invoice status', 'invoicing' ),
104
		'wpi-cancelled'  => _x( 'Cancelled', 'Invoice status', 'invoicing' ),
105
		'wpi-refunded'   => _x( 'Refunded', 'Invoice status', 'invoicing' ),
106
        'wpi-failed'     => _x( 'Failed', 'Invoice status', 'invoicing' ),
107
        'wpi-renewal'    => _x( 'Renewal Payment', 'Invoice status', 'invoicing' ),
108
    );
109
110
    if ( $draft ) {
111
        $invoice_statuses['draft'] = __( 'Draft', 'invoicing' );
112
    }
113
114
    if ( $trashed ) {
115
        $invoice_statuses['trash'] = __( 'Trash', 'invoicing' );
116
    }
117
118
	return apply_filters( 'wpinv_statuses', $invoice_statuses, $invoice );
119
}
120
121
function wpinv_status_nicename( $status ) {
122
    $statuses = wpinv_get_invoice_statuses( true, true );
123
    $status   = isset( $statuses[$status] ) ? $statuses[$status] : __( $status, 'invoicing' );
124
125
    return $status;
126
}
127
128
/**
129
 * Retrieves the default currency code.
130
 */
131
function wpinv_get_currency() {
132
    return apply_filters( 'wpinv_currency', wpinv_get_option( 'currency', 'USD' ) );
133
}
134
135
/**
136
 * Given a currency, it returns a currency symbol.
137
 * 
138
 * @param string|null $currency The currency code. Defaults to the default currency.
139
 */
140
function wpinv_currency_symbol( $currency = null ) {
141
142
    // Prepare the currency.
143
    $currency = empty( $currency ) ? wpinv_get_currency() : wpinv_clean( $currency );
144
145
    // Fetch all symbols.
146
    $symbols = wpinv_get_currency_symbols();
147
148
    // Fetch this currencies symbol.
149
    $currency_symbol = isset( $symbols[$currency] ) ? $symbols[$currency] : $currency;
150
151
    // Filter the symbol.
152
    return apply_filters( 'wpinv_currency_symbol', $currency_symbol, $currency );
153
}
154
155
function wpinv_currency_position() {
156
    $position = wpinv_get_option( 'currency_position', 'left' );
157
    
158
    return apply_filters( 'wpinv_currency_position', $position );
159
}
160
161
function wpinv_thousands_separator() {
162
    $thousand_sep = wpinv_get_option( 'thousands_separator', ',' );
163
    
164
    return apply_filters( 'wpinv_thousands_separator', $thousand_sep );
165
}
166
167
function wpinv_decimal_separator() {
168
    $decimal_sep = wpinv_get_option( 'decimal_separator', '.' );
169
    
170
    return apply_filters( 'wpinv_decimal_separator', $decimal_sep );
171
}
172
173
function wpinv_decimals() {
174
    $decimals = apply_filters( 'wpinv_decimals', wpinv_get_option( 'decimals', 2 ) );
175
    
176
    return absint( $decimals );
177
}
178
179
/**
180
 * Retrieves a list of all supported currencies.
181
 */
182
function wpinv_get_currencies() {
183
    return apply_filters( 'wpinv_currencies', wpinv_get_data( 'currencies' ) );
184
}
185
186
/**
187
 * Retrieves a list of all currency symbols.
188
 */
189
function wpinv_get_currency_symbols() {
190
    return apply_filters( 'wpinv_currency_symbols', wpinv_get_data( 'currency-symbols' ) );
191
}
192
193
function wpinv_price( $amount = '', $currency = '' ) {
194
    if( empty( $currency ) ) {
195
        $currency = wpinv_get_currency();
196
    }
197
198
    $position = wpinv_currency_position();
199
200
    $negative = $amount < 0;
201
202
    if ( $negative ) {
203
        $amount = substr( $amount, 1 );
204
    }
205
206
    $symbol = wpinv_currency_symbol( $currency );
207
208
    if ( $position == 'left' || $position == 'left_space' ) {
209
        switch ( $currency ) {
210
            case "GBP" :
211
            case "BRL" :
212
            case "EUR" :
213
            case "USD" :
214
            case "AUD" :
215
            case "CAD" :
216
            case "HKD" :
217
            case "MXN" :
218
            case "NZD" :
219
            case "SGD" :
220
            case "JPY" :
221
                $price = $position == 'left_space' ? $symbol . ' ' .  $amount : $symbol . $amount;
0 ignored issues
show
Bug introduced by
Are you sure $symbol of type array|mixed|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

221
                $price = $position == 'left_space' ? /** @scrutinizer ignore-type */ $symbol . ' ' .  $amount : $symbol . $amount;
Loading history...
222
                break;
223
            default :
224
                //$price = $currency . ' ' . $amount;
225
                $price = $position == 'left_space' ? $symbol . ' ' .  $amount : $symbol . $amount;
226
                break;
227
        }
228
    } else {
229
        switch ( $currency ) {
230
            case "GBP" :
231
            case "BRL" :
232
            case "EUR" :
233
            case "USD" :
234
            case "AUD" :
235
            case "CAD" :
236
            case "HKD" :
237
            case "MXN" :
238
            case "SGD" :
239
            case "JPY" :
240
                $price = $position == 'right_space' ? $amount . ' ' .  $symbol : $amount . $symbol;
241
                break;
242
            default :
243
                //$price = $amount . ' ' . $currency;
244
                $price = $position == 'right_space' ? $amount . ' ' .  $symbol : $amount . $symbol;
245
                break;
246
        }
247
    }
248
    
249
    if ( $negative ) {
250
        $price = '-' . $price;
251
    }
252
    
253
    $price = apply_filters( 'wpinv_' . strtolower( $currency ) . '_currency_filter_' . $position, $price, $currency, $amount );
254
255
    return $price;
256
}
257
258
function wpinv_format_amount( $amount, $decimals = NULL, $calculate = false ) {
259
    $thousands_sep = wpinv_thousands_separator();
260
    $decimal_sep   = wpinv_decimal_separator();
261
262
    if ( $decimals === NULL ) {
263
        $decimals = wpinv_decimals();
264
    }
265
266
    if ( $decimal_sep == ',' && false !== ( $sep_found = strpos( $amount, $decimal_sep ) ) ) {
267
        $whole = substr( $amount, 0, $sep_found );
268
        $part = substr( $amount, $sep_found + 1, ( strlen( $amount ) - 1 ) );
269
        $amount = $whole . '.' . $part;
270
    }
271
272
    if ( $thousands_sep == ',' && false !== ( $found = strpos( $amount, $thousands_sep ) ) ) {
0 ignored issues
show
Unused Code introduced by
The assignment to $found is dead and can be removed.
Loading history...
273
        $amount = str_replace( ',', '', $amount );
274
    }
275
276
    if ( $thousands_sep == ' ' && false !== ( $found = strpos( $amount, $thousands_sep ) ) ) {
277
        $amount = str_replace( ' ', '', $amount );
278
    }
279
280
    if ( empty( $amount ) ) {
281
        $amount = 0;
282
    }
283
    
284
    $decimals  = apply_filters( 'wpinv_amount_format_decimals', $decimals ? $decimals : 0, $amount, $calculate );
285
    $formatted = number_format( (float)$amount, $decimals, $decimal_sep, $thousands_sep );
286
    
287
    if ( $calculate ) {
288
        if ( $thousands_sep === "," ) {
289
            $formatted = str_replace( ",", "", $formatted );
290
        }
291
        
292
        if ( $decimal_sep === "," ) {
293
            $formatted = str_replace( ",", ".", $formatted );
294
        }
295
    }
296
297
    return apply_filters( 'wpinv_amount_format', $formatted, $amount, $decimals, $decimal_sep, $thousands_sep, $calculate );
298
}
299
add_filter( 'wpinv_amount_format_decimals', 'wpinv_currency_decimal_filter', 10, 1 );
300
301
function wpinv_sanitize_key( $key ) {
302
    $raw_key = $key;
303
    $key = preg_replace( '/[^a-zA-Z0-9_\-\.\:\/]/', '', $key );
304
305
    return apply_filters( 'wpinv_sanitize_key', $key, $raw_key );
306
}
307
308
function wpinv_get_file_extension( $str ) {
309
    $parts = explode( '.', $str );
310
    return end( $parts );
311
}
312
313
function wpinv_string_is_image_url( $str ) {
314
    $ext = wpinv_get_file_extension( $str );
315
316
    switch ( strtolower( $ext ) ) {
317
        case 'jpeg';
318
        case 'jpg';
319
            $return = true;
320
            break;
321
        case 'png';
322
            $return = true;
323
            break;
324
        case 'gif';
325
            $return = true;
326
            break;
327
        default:
328
            $return = false;
329
            break;
330
    }
331
332
    return (bool)apply_filters( 'wpinv_string_is_image', $return, $str );
333
}
334
335
function wpinv_error_log( $log, $title = '', $file = '', $line = '', $exit = false ) {
336
    $should_log = apply_filters( 'wpinv_log_errors', WP_DEBUG );
337
    
338
    if ( true === $should_log ) {
339
        $label = '';
340
        if ( $file && $file !== '' ) {
341
            $label .= basename( $file ) . ( $line ? '(' . $line . ')' : '' );
342
        }
343
        
344
        if ( $title && $title !== '' ) {
345
            $label = $label !== '' ? $label . ' ' : '';
346
            $label .= $title . ' ';
347
        }
348
        
349
        $label = $label !== '' ? trim( $label ) . ' : ' : '';
350
        
351
        if ( is_array( $log ) || is_object( $log ) ) {
352
            error_log( $label . print_r( $log, true ) );
353
        } else {
354
            error_log( $label . $log );
355
        }
356
357
        error_log( wp_debug_backtrace_summary() );
358
        if ( $exit ) {
359
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
360
        }
361
    }
362
}
363
364
function wpinv_is_ajax_disabled() {
365
    $retval = false;
366
    return apply_filters( 'wpinv_is_ajax_disabled', $retval );
367
}
368
369
function wpinv_get_current_page_url( $nocache = false ) {
370
    global $wp;
371
372
    if ( get_option( 'permalink_structure' ) ) {
373
        $base = trailingslashit( home_url( $wp->request ) );
374
    } else {
375
        $base = add_query_arg( $wp->query_string, '', trailingslashit( home_url( $wp->request ) ) );
376
        $base = remove_query_arg( array( 'post_type', 'name' ), $base );
377
    }
378
379
    $scheme = is_ssl() ? 'https' : 'http';
380
    $uri    = set_url_scheme( $base, $scheme );
381
382
    if ( is_front_page() ) {
383
        $uri = home_url( '/' );
384
    } elseif ( wpinv_is_checkout( array(), false ) ) {
0 ignored issues
show
Unused Code introduced by
The call to wpinv_is_checkout() has too many arguments starting with array(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

384
    } elseif ( /** @scrutinizer ignore-call */ wpinv_is_checkout( array(), false ) ) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
385
        $uri = wpinv_get_checkout_uri();
386
    }
387
388
    $uri = apply_filters( 'wpinv_get_current_page_url', $uri );
389
390
    if ( $nocache ) {
391
        $uri = wpinv_add_cache_busting( $uri );
0 ignored issues
show
Bug introduced by
The function wpinv_add_cache_busting was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

391
        $uri = /** @scrutinizer ignore-call */ wpinv_add_cache_busting( $uri );
Loading history...
392
    }
393
394
    return $uri;
395
}
396
397
/**
398
 * Define a constant if it is not already defined.
399
 *
400
 * @since 1.0.19
401
 * @param string $name  Constant name.
402
 * @param mixed  $value Value.
403
 */
404
function getpaid_maybe_define_constant( $name, $value ) {
405
	if ( ! defined( $name ) ) {
406
		define( $name, $value );
407
	}
408
}
409
410
function wpinv_get_php_arg_separator_output() {
411
	return ini_get( 'arg_separator.output' );
412
}
413
414
function wpinv_rgb_from_hex( $color ) {
415
    $color = str_replace( '#', '', $color );
416
417
    // Convert shorthand colors to full format, e.g. "FFF" -> "FFFFFF"
418
    $color = preg_replace( '~^(.)(.)(.)$~', '$1$1$2$2$3$3', $color );
419
    if ( empty( $color ) ) {
420
        return NULL;
421
    }
422
423
    $color = str_split( $color );
424
425
    $rgb      = array();
426
    $rgb['R'] = hexdec( $color[0] . $color[1] );
427
    $rgb['G'] = hexdec( $color[2] . $color[3] );
428
    $rgb['B'] = hexdec( $color[4] . $color[5] );
429
430
    return $rgb;
431
}
432
433
function wpinv_hex_darker( $color, $factor = 30 ) {
434
    $base  = wpinv_rgb_from_hex( $color );
435
    $color = '#';
436
437
    foreach ( $base as $k => $v ) {
438
        $amount      = $v / 100;
439
        $amount      = round( $amount * $factor );
440
        $new_decimal = $v - $amount;
441
442
        $new_hex_component = dechex( $new_decimal );
0 ignored issues
show
Bug introduced by
$new_decimal of type double is incompatible with the type integer expected by parameter $number of dechex(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

442
        $new_hex_component = dechex( /** @scrutinizer ignore-type */ $new_decimal );
Loading history...
443
        if ( strlen( $new_hex_component ) < 2 ) {
444
            $new_hex_component = "0" . $new_hex_component;
445
        }
446
        $color .= $new_hex_component;
447
    }
448
449
    return $color;
450
}
451
452
function wpinv_hex_lighter( $color, $factor = 30 ) {
453
    $base  = wpinv_rgb_from_hex( $color );
454
    $color = '#';
455
456
    foreach ( $base as $k => $v ) {
457
        $amount      = 255 - $v;
458
        $amount      = $amount / 100;
459
        $amount      = round( $amount * $factor );
460
        $new_decimal = $v + $amount;
461
462
        $new_hex_component = dechex( $new_decimal );
0 ignored issues
show
Bug introduced by
$new_decimal of type double is incompatible with the type integer expected by parameter $number of dechex(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

462
        $new_hex_component = dechex( /** @scrutinizer ignore-type */ $new_decimal );
Loading history...
463
        if ( strlen( $new_hex_component ) < 2 ) {
464
            $new_hex_component = "0" . $new_hex_component;
465
        }
466
        $color .= $new_hex_component;
467
    }
468
469
    return $color;
470
}
471
472
function wpinv_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) {
473
    $hex = str_replace( '#', '', $color );
474
475
    $c_r = hexdec( substr( $hex, 0, 2 ) );
476
    $c_g = hexdec( substr( $hex, 2, 2 ) );
477
    $c_b = hexdec( substr( $hex, 4, 2 ) );
478
479
    $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;
480
481
    return $brightness > 155 ? $dark : $light;
482
}
483
484
function wpinv_format_hex( $hex ) {
485
    $hex = trim( str_replace( '#', '', $hex ) );
486
487
    if ( strlen( $hex ) == 3 ) {
488
        $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
489
    }
490
491
    return $hex ? '#' . $hex : null;
492
}
493
494
/**
495
 * Get truncated string with specified width.
496
 *
497
 * @since 1.0.0
498
 *
499
 * @param string $str The string being decoded.
500
 * @param int $start The start position offset. Number of characters from the beginning of string.
501
 *                      For negative value, number of characters from the end of the string.
502
 * @param int $width The width of the desired trim. Negative widths count from the end of the string.
503
 * @param string $trimmaker A string that is added to the end of string when string is truncated. Ex: "...".
504
 * @param string $encoding The encoding parameter is the character encoding. Default "UTF-8".
505
 * @return string
506
 */
507
function wpinv_utf8_strimwidth( $str, $start, $width, $trimmaker = '', $encoding = 'UTF-8' ) {
508
    if ( function_exists( 'mb_strimwidth' ) ) {
509
        return mb_strimwidth( $str, $start, $width, $trimmaker, $encoding );
510
    }
511
    
512
    return wpinv_utf8_substr( $str, $start, $width, $encoding ) . $trimmaker;
513
}
514
515
/**
516
 * Get the string length.
517
 *
518
 * @since 1.0.0
519
 *
520
 * @param string $str The string being checked for length. 
521
 * @param string $encoding The encoding parameter is the character encoding. Default "UTF-8".
522
 * @return int Returns the number of characters in string.
523
 */
524
function wpinv_utf8_strlen( $str, $encoding = 'UTF-8' ) {
525
    if ( function_exists( 'mb_strlen' ) ) {
526
        return mb_strlen( $str, $encoding );
527
    }
528
        
529
    return strlen( $str );
530
}
531
532
function wpinv_utf8_strtolower( $str, $encoding = 'UTF-8' ) {
533
    if ( function_exists( 'mb_strtolower' ) ) {
534
        return mb_strtolower( $str, $encoding );
535
    }
536
    
537
    return strtolower( $str );
538
}
539
540
function wpinv_utf8_strtoupper( $str, $encoding = 'UTF-8' ) {
541
    if ( function_exists( 'mb_strtoupper' ) ) {
542
        return mb_strtoupper( $str, $encoding );
543
    }
544
    
545
    return strtoupper( $str );
546
}
547
548
/**
549
 * Find position of first occurrence of string in a string
550
 *
551
 * @since 1.0.0
552
 *
553
 * @param string $str The string being checked.
554
 * @param string $find The string to find in input string.
555
 * @param int $offset The search offset. Default "0". A negative offset counts from the end of the string.
556
 * @param string $encoding The encoding parameter is the character encoding. Default "UTF-8".
557
 * @return int Returns the position of the first occurrence of search in the string.
558
 */
559
function wpinv_utf8_strpos( $str, $find, $offset = 0, $encoding = 'UTF-8' ) {
560
    if ( function_exists( 'mb_strpos' ) ) {
561
        return mb_strpos( $str, $find, $offset, $encoding );
562
    }
563
        
564
    return strpos( $str, $find, $offset );
565
}
566
567
/**
568
 * Find position of last occurrence of a string in a string.
569
 *
570
 * @since 1.0.0
571
 *
572
 * @param string $str The string being checked, for the last occurrence of search.
573
 * @param string $find The string to find in input string.
574
 * @param int $offset Specifies begin searching an arbitrary number of characters into the string.
575
 * @param string $encoding The encoding parameter is the character encoding. Default "UTF-8".
576
 * @return int Returns the position of the last occurrence of search.
577
 */
578
function wpinv_utf8_strrpos( $str, $find, $offset = 0, $encoding = 'UTF-8' ) {
579
    if ( function_exists( 'mb_strrpos' ) ) {
580
        return mb_strrpos( $str, $find, $offset, $encoding );
581
    }
582
        
583
    return strrpos( $str, $find, $offset );
584
}
585
586
/**
587
 * Get the part of string.
588
 *
589
 * @since 1.0.0
590
 *
591
 * @param string $str The string to extract the substring from.
592
 * @param int $start If start is non-negative, the returned string will start at the entered position in string, counting from zero.
593
 *                      If start is negative, the returned string will start at the entered position from the end of string. 
594
 * @param int|null $length Maximum number of characters to use from string.
595
 * @param string $encoding The encoding parameter is the character encoding. Default "UTF-8".
596
 * @return string
597
 */
598
function wpinv_utf8_substr( $str, $start, $length = null, $encoding = 'UTF-8' ) {
599
    if ( function_exists( 'mb_substr' ) ) {
600
        if ( $length === null ) {
601
            return mb_substr( $str, $start, wpinv_utf8_strlen( $str, $encoding ), $encoding );
602
        } else {
603
            return mb_substr( $str, $start, $length, $encoding );
604
        }
605
    }
606
        
607
    return substr( $str, $start, $length );
608
}
609
610
/**
611
 * Get the width of string.
612
 *
613
 * @since 1.0.0
614
 *
615
 * @param string $str The string being decoded.
616
 * @param string $encoding The encoding parameter is the character encoding. Default "UTF-8".
617
 * @return string The width of string.
618
 */
619
function wpinv_utf8_strwidth( $str, $encoding = 'UTF-8' ) {
620
    if ( function_exists( 'mb_strwidth' ) ) {
621
        return mb_strwidth( $str, $encoding );
622
    }
623
    
624
    return wpinv_utf8_strlen( $str, $encoding );
625
}
626
627
function wpinv_utf8_ucfirst( $str, $lower_str_end = false, $encoding = 'UTF-8' ) {
628
    if ( function_exists( 'mb_strlen' ) ) {
629
        $first_letter = wpinv_utf8_strtoupper( wpinv_utf8_substr( $str, 0, 1, $encoding ), $encoding );
630
        $str_end = "";
631
        
632
        if ( $lower_str_end ) {
633
            $str_end = wpinv_utf8_strtolower( wpinv_utf8_substr( $str, 1, wpinv_utf8_strlen( $str, $encoding ), $encoding ), $encoding );
634
        } else {
635
            $str_end = wpinv_utf8_substr( $str, 1, wpinv_utf8_strlen( $str, $encoding ), $encoding );
636
        }
637
638
        return $first_letter . $str_end;
639
    }
640
    
641
    return ucfirst( $str );
642
}
643
644
function wpinv_utf8_ucwords( $str, $encoding = 'UTF-8' ) {
645
    if ( function_exists( 'mb_convert_case' ) ) {
646
        return mb_convert_case( $str, MB_CASE_TITLE, $encoding );
647
    }
648
    
649
    return ucwords( $str );
650
}
651
652
function wpinv_period_in_days( $period, $unit ) {
653
    $period = absint( $period );
654
    
655
    if ( $period > 0 ) {
656
        if ( in_array( strtolower( $unit ), array( 'w', 'week', 'weeks' ) ) ) {
657
            $period = $period * 7;
658
        } else if ( in_array( strtolower( $unit ), array( 'm', 'month', 'months' ) ) ) {
659
            $period = $period * 30;
660
        } else if ( in_array( strtolower( $unit ), array( 'y', 'year', 'years' ) ) ) {
661
            $period = $period * 365;
662
        }
663
    }
664
    
665
    return $period;
666
}
667
668
function wpinv_cal_days_in_month( $calendar, $month, $year ) {
669
    if ( function_exists( 'cal_days_in_month' ) ) {
670
        return cal_days_in_month( $calendar, $month, $year );
671
    }
672
673
    // Fallback in case the calendar extension is not loaded in PHP
674
    // Only supports Gregorian calendar
675
    return date( 't', mktime( 0, 0, 0, $month, 1, $year ) );
676
}
677
678
/**
679
 * Display a help tip for settings.
680
 *
681
 * @param  string $tip Help tip text
682
 * @param  bool $allow_html Allow sanitized HTML if true or escape
683
 *
684
 * @return string
685
 */
686
function wpi_help_tip( $tip, $allow_html = false ) {
687
    if ( $allow_html ) {
688
        $tip = wpi_sanitize_tooltip( $tip );
689
    } else {
690
        $tip = esc_attr( $tip );
691
    }
692
693
    return '<span class="wpi-help-tip dashicons dashicons-editor-help" title="' . $tip . '"></span>';
694
}
695
696
/**
697
 * Sanitize a string destined to be a tooltip.
698
 *
699
 * Tooltips are encoded with htmlspecialchars to prevent XSS. Should not be used in conjunction with esc_attr()
700
 *
701
 * @param string $var
702
 * @return string
703
 */
704
function wpi_sanitize_tooltip( $var ) {
705
    return htmlspecialchars( wp_kses( html_entity_decode( $var ), array(
706
        'br'     => array(),
707
        'em'     => array(),
708
        'strong' => array(),
709
        'small'  => array(),
710
        'span'   => array(),
711
        'ul'     => array(),
712
        'li'     => array(),
713
        'ol'     => array(),
714
        'p'      => array(),
715
    ) ) );
716
}
717
718
/**
719
 * Get all WPI screen ids.
720
 *
721
 * @return array
722
 */
723
function wpinv_get_screen_ids() {
724
725
    $screen_id = sanitize_title( __( 'Invoicing', 'invoicing' ) );
726
727
    $screen_ids = array(
728
        'toplevel_page_' . $screen_id,
729
        'wpi_invoice',
730
        'wpi_item',
731
        'wpi_quote',
732
        'wpi_discount',
733
        'edit-wpi_invoice',
734
        'edit-wpi_item',
735
        'edit-wpi_discount',
736
        'edit-wpi_quote',
737
        'invoicing_page_wpinv-settings',
738
        'invoicing_page_wpinv-subscriptions',
739
        'invoicing_page_wpinv-reports',
740
        'invoicing_page_wpi-addons',
741
    );
742
743
    return apply_filters( 'wpinv_screen_ids', $screen_ids );
744
}
745
746
/**
747
 * Cleans up an array, comma- or space-separated list of scalar values.
748
 *
749
 * @since 1.0.13
750
 *
751
 * @param array|string $list List of values.
752
 * @return array Sanitized array of values.
753
 */
754
function wpinv_parse_list( $list ) {
755
756
    if ( empty( $list ) ) {
757
        $list = array();
758
    }
759
760
	if ( ! is_array( $list ) ) {
761
		return preg_split( '/[\s,]+/', $list, -1, PREG_SPLIT_NO_EMPTY );
0 ignored issues
show
Bug Best Practice introduced by
The expression return preg_split('/[\s,...1, PREG_SPLIT_NO_EMPTY) could also return false which is incompatible with the documented return type array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
762
	}
763
764
	return $list;
765
}
766
767
/**
768
 * Fetches data stored on disk.
769
 *
770
 * @since 1.0.14
771
 *
772
 * @param string $key Type of data to fetch.
773
 * @return mixed Fetched data.
774
 */
775
function wpinv_get_data( $key ) {
776
777
    // Try fetching it from the cache.
778
    $data = wp_cache_get( "wpinv-data-$key", 'wpinv' );
779
    if( $data ) {
780
        return $data;
781
    }
782
783
    $data = apply_filters( "wpinv_get_$key", include WPINV_PLUGIN_DIR . "includes/data/$key.php" );
784
	wp_cache_set( "wpinv-data-$key", $data, 'wpinv' );
785
786
	return $data;
787
}
788
789
/**
790
 * (Maybe) Adds an empty option to an array of options.
791
 *
792
 * @since 1.0.14
793
 *
794
 * @param array $options
795
 * @param bool $first_empty Whether or not the first item in the list should be empty
796
 * @return mixed Fetched data.
797
 */
798
function wpinv_maybe_add_empty_option( $options, $first_empty ) {
799
800
    if ( ! empty( $options ) && $first_empty ) {
801
        return array_merge( array( '' => '' ), $options );
802
    }
803
    return $options;
804
805
}
806
807
/**
808
 * Clean variables using sanitize_text_field.
809
 *
810
 * @param mixed $var Data to sanitize.
811
 * @return string|array
812
 */
813
function wpinv_clean( $var ) {
814
815
	if ( is_array( $var ) ) {
816
		return array_map( 'wpinv_clean', $var );
817
    }
818
819
    if ( is_object( $var ) ) {
820
		$object_vars = get_object_vars( $var );
821
		foreach ( $object_vars as $property_name => $property_value ) {
822
			$var->$property_name = wpinv_clean( $property_value );
823
        }
824
        return $var;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $var returns the type object which is incompatible with the documented return type array|string.
Loading history...
825
	}
826
    
827
    return is_string( $var ) ? sanitize_text_field( $var ) : $var;
828
}
829
830
/**
831
 * Converts a price string into an options array.
832
 *
833
 * @param string $str Data to convert.
834
 * @return string|array
835
 */
836
function getpaid_convert_price_string_to_options( $str ) {
837
838
	$raw_options = array_map( 'trim', explode( ',', $str ) );
839
    $options     = array();
840
841
    foreach ( $raw_options as $option ) {
842
843
        if ( '' == $option ) {
844
            continue;
845
        }
846
847
        $option = array_map( 'trim', explode( '|', $option ) );
848
849
        $price = null;
850
        $label = null;
851
852
        if ( isset( $option[0] ) && '' !=  $option[0] ) {
853
            $label  = $option[0];
854
        }
855
856
        if ( isset( $option[1] ) && '' !=  $option[1] ) {
857
            $price = $option[1];
858
        }
859
860
        if ( ! isset( $price ) ) {
861
            $price = $label;
862
        }
863
864
        if ( ! isset( $price ) || ! is_numeric( $price ) ) {
865
            continue;
866
        }
867
868
        if ( ! isset( $label ) ) {
869
            $label = $price;
870
        }
871
872
        $options[ $price ] = $label;
873
    }
874
875
    return $options;
876
}
877
878
/**
879
 * Returns the help tip.
880
 */
881
function getpaid_get_help_tip( $tip, $additional_classes = '' ) {
882
    $additional_classes = sanitize_html_class( $additional_classes );
883
    $tip                = esc_attr__( $tip );
884
    return "<span class='wpi-help-tip dashicons dashicons-editor-help $additional_classes' title='$tip'></span>";
885
}
886
887
/**
888
 * Formats a date
889
 */
890
function getpaid_format_date( $date ) {
891
892
    if ( empty( $date ) || $date == '0000-00-00 00:00:00' ) {
893
        return '';
894
    }
895
896
897
    return date_i18n( get_option( 'date_format' ), strtotime( $date ) );
0 ignored issues
show
Bug introduced by
It seems like get_option('date_format') can also be of type false; however, parameter $format of date_i18n() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

897
    return date_i18n( /** @scrutinizer ignore-type */ get_option( 'date_format' ), strtotime( $date ) );
Loading history...
898
899
}
900
901
/**
902
 * Limit length of a string.
903
 *
904
 * @param  string  $string string to limit.
905
 * @param  integer $limit Limit size in characters.
906
 * @return string
907
 */
908
function getpaid_limit_length( $string, $limit ) {
909
    $str_limit = $limit - 3;
910
911
	if ( function_exists( 'mb_strimwidth' ) ) {
912
		if ( mb_strlen( $string ) > $limit ) {
913
			$string = mb_strimwidth( $string, 0, $str_limit ) . '...';
914
		}
915
	} else {
916
		if ( strlen( $string ) > $limit ) {
917
			$string = substr( $string, 0, $str_limit ) . '...';
918
		}
919
	}
920
    return $string;
921
922
}
923