helpers.php ➔ debug()   C
last analyzed

Complexity

Conditions 14
Paths 4

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
nc 4
nop 1
dl 0
loc 51
rs 6.2666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
if (!function_exists('rgb2hex')) {
4
5
    /**
6
     * @param int $red
7
     * @param int $green
8
     * @param int $blue
9
     * @return string
10
     * @see https://gist.github.com/Pushplaybang/5432844
11
     */
12
    function rgb2hex(int $red, int $green, int $blue):  string
13
    {
14
        $hex = "#";
15
        $hex .= str_pad(dechex($red), 2, "0", STR_PAD_LEFT);
16
        $hex .= str_pad(dechex($green), 2, "0", STR_PAD_LEFT);
17
        $hex .= str_pad(dechex($blue), 2, "0", STR_PAD_LEFT);
18
19
        return $hex; // returns the hex value including the number sign (#)
20
    }
21
}
22
23
if (!function_exists('hex2rgb')) {
24
25
    /**
26
     * Takes HEX color code value and converts to a RGB value.
27
     *
28
     * @param string $color Color hex value, example: #000000, #000 or 000000, 000
29
     *
30
     * @return string color rbd value
31
     */
32
    function hex2rgb($color)
33
    {
34
        $color = str_replace('#', '', $color);
35
        if (strlen($color) == 3):
36
            list($r, $g, $b) = [$color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2]];
37
        else:
38
            list($r, $g, $b) = [$color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5]];
39
        endif;
40
        $r = hexdec($r);
41
        $g = hexdec($g);
42
        $b = hexdec($b);
43
        return 'rgb(' . $r . ', ' . $g . ', ' . $b . ')';
44
    }
45
}
46
47
/**
48
 * @param float $val
49
 * @param int $precision
50
 * @param string $simbol
51
 * @param bool $prepend if true (default) prefix with $simbol, otherwise suffix with $simbol.
52
 * @return string
53
 */
54
function format_money(float $val = 0.00, int $precision = 2, string $simbol = "", bool $prepend=true) : string
55
{
56
    $prefix = $simbol.' ';
57
    $suffix = '';
58
    if(!$prepend){
59
        $prefix = '';
60
        $suffix = ' '.$simbol;
61
    }
62
    return trim($prefix . number_format($val, $precision, ',', '.').$suffix);
63
}
64
65
/**
66
 * Format float 1125.86 into string '&euro 1.125,86'
67
 * @param float $val
68
 * @param bool $prepend if true (default) prefix with '&euro; ', otherwise suffix with ' &euro;'.
69
 * @return string
70
 */
71
function format_euro(float $val = 0.00, bool $prepend=true) : string
72
{
73
    return format_money($val, 2, '&euro; ', $prepend);
74
}
75
76
if (!function_exists('ordinal')) {
77
78
    /**
79
     * Given a number, return the number + 'th' or 'rd' etc
80
     * @param $cdnl
81
     * @return string
82
     */
83
    function ordinal($cdnl)
84
    {
85
        $test_c = abs($cdnl) % 10;
86
        $ext = ((abs($cdnl) % 100 < 21 && abs($cdnl) % 100 > 4) ? 'th'
87
            : (($test_c < 4) ? ($test_c < 3) ? ($test_c < 2) ? ($test_c < 1)
88
                ? 'th' : 'st' : 'nd' : 'rd' : 'th'));
89
        return $cdnl . $ext;
90
    }
91
}
92
93
if (!function_exists('value')) {
94
    /**
95
     * Return the default value of the given value.
96
     *
97
     * @param  mixed $value
98
     * @return mixed
99
     */
100
    function value($value)
101
    {
102
        return $value instanceof Closure ? $value() : $value;
103
    }
104
}
105
if (!function_exists('with')) {
106
    /**
107
     * Return the given object. Useful for chaining.
108
     *
109
     * @param  mixed $object
110
     * @return mixed
111
     */
112
    function with($object)
113
    {
114
        return $object;
115
    }
116
}
117
118
/**
119
 * Set the default configuration of erro reporting for production.
120
 */
121
function setErrorReportingForProduction()
122
{
123
    if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
124
        error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT);
125
    } elseif (version_compare(PHP_VERSION, '5.3.0') >= 0) {
126
        error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);
127
    } else {
128
        error_reporting(E_ALL ^ E_NOTICE);
129
    }
130
}
131
132
/**
133
 * Check if PHP script was executed by shell.
134
 * @return bool
135
 */
136
function isExecutedByCLI() : bool
137
{
138
    return php_sapi_name() == 'cli';
139
}
140
141
/**
142
 * Convert the output of PHP's filesize() function
143
 * to a nice format with PB, TB, GB, MB, kB, bytes.
144
 * @param $bytes
145
 * @param int $decimals [optional] default 0. Sets the number of decimal points.
146
 * @return string
147
 */
148
function bytes2HumanSize($bytes, $decimals=0)
149
{
150
    if(!isIntegerPositiveOrZero($decimals)){
151
        $decimals = 0;
152
    }
153
154
    if ($bytes >= 1125899906842624) {
155
        $bytes = number_format($bytes / 1073741824, $decimals) . ' PB';
156
    } elseif ($bytes >= 1099511627776) {
157
        $bytes = number_format($bytes / 1073741824, $decimals) . ' TB';
158
    } elseif ($bytes >= 1073741824) {
159
        $bytes = number_format($bytes / 1073741824, $decimals) . ' GB';
160
    } elseif ($bytes >= 1048576) {
161
        $bytes = number_format($bytes / 1048576, $decimals) . ' MB';
162
    } elseif ($bytes >= 1024) {
163
        $bytes = number_format($bytes / 1024, $decimals) . ' kB';
164
    } elseif ($bytes > 1) {
165
        $bytes .= ' bytes';
166
    } elseif ($bytes == 1) {
167
        $bytes .= ' byte';
168
    } else {
169
        $bytes = '0 bytes';
170
    }
171
172
    return $bytes;
173
}
174
175
/**
176
 * This function transforms the php.ini notation for numbers (like '2M')
177
 * to an integer (2*1024*1024 in this case)
178
 * @param string $sSize
179
 * @return int|string
180
 */
181
function convertPHPSizeToBytes($sSize)
182
{
183
    if (is_numeric($sSize)) {
184
        return $sSize;
185
    }
186
    $sSuffix = substr($sSize, -1);
187
    $iValue = substr($sSize, 0, -1);
188
189
    switch (strtoupper($sSuffix)) {
190
        case 'P':
191
            $iValue *= 1024;
192
        //PB multiplier
193
        case 'T':
194
            $iValue *= 1024;
195
        //TB multiplier
196
        case 'G':
197
            $iValue *= 1024;
198
        //GB multiplier
199
        case 'M':
200
            $iValue *= 1024;
201
        //MB multiplier
202
        case 'K':
203
            $iValue *= 1024;
204
            //KB multiplier
205
            break;
206
    }
207
    return $iValue;
208
}
209
210
/**
211
 * Return the Max upload size in bytes.
212
 * @param bool $humanFormat if set to true return size in human format (MB, kB, etc..) otherwise return in bytes.
213
 * @return int
214
 */
215
function getMaximumFileUploadSize(bool $humanFormat = false)
216
{
217
    $size = min(convertPHPSizeToBytes(ini_get('post_max_size')), convertPHPSizeToBytes(ini_get('upload_max_filesize')));
218
219
    if (!$humanFormat) {
220
        return $size;
221
    }
222
223
    return bytes2HumanSize($size);
224
}
225
226
/**
227
 * Encrypt string in asymmetrical way.
228
 * @param string $string to encrypt.
229
 * @param string $chiave the key to encrypt. if empty generate a random key on the fly.
230
 * @return string
231
 */
232
function encryptString(string $string, string $chiave = '')
233
{
234
    if ($chiave == '') {
235
        $chiave = str_random(64);
236
    }
237
238
    $key = pack('H*', $chiave);
239
240
    $plaintext = $string;
241
242
    # create a random IV to use with CBC encoding
243
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
244
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
245
246
    # creates a cipher text compatible with AES (Rijndael block size = 128)
247
    # to keep the text confidential
248
    # only suitable for encoded input that never ends with value 00h
249
    # (because of default zero padding)
250
    $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
251
252
    # prepend the IV for it to be available for decryption
253
    $ciphertext = $iv . $ciphertext;
254
255
    # encode the resulting cipher text so it can be represented by a string
256
    $ciphertext_base64 = base64_encode($ciphertext);
257
258
    return $ciphertext_base64;
259
}
260
261
/**
262
 * Get a Website favicon url.
263
 *
264
 * @param string $url website url
265
 *
266
 * @return string containing complete image tag
267
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
268
 */
269
function getFaviconUrl($url) : string
270
{
271
    $apiUrl = 'https://www.google.com/s2/favicons?domain=';
272
    if (strpos($url, 'http') !== false) {
273
        $url = str_replace('http://', '', $url);
274
    }
275
    return $apiUrl . $url;
276
}
277
278
/**
279
 * Get a Website favicon image tag.
280
 *
281
 * @param string $url website url
282
 * @param array $attributes Optional, additional key/value attributes to include in the IMG tag
283
 *
284
 * @return string containing complete image tag
285
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
286
 */
287
function getFaviconImgTag($url, array $attributes = []) : string
288
{
289
    $urlFav = getFaviconUrl($url);
290
    $attr = arrayToString($attributes);
291
    return '<img src="' . $urlFav . '" ' . trim($attr) . ' />';
292
}
293
294
/**
295
 * Check to see if the current page is being server over SSL or not.
296
 * Support HTTP_X_FORWARDED_PROTO to check ssl over proxy/load balancer.
297
 *
298
 * @return bool
299
 */
300
function isHttps()
301
{
302
    $key = 'HTTPS';
303
    if (isNotNullOrEmptyArrayKey($_SERVER, 'HTTP_X_FORWARDED_PROTO')) {
304
        $key = 'HTTP_X_FORWARDED_PROTO';
305
    }
306
    return isNotNullOrEmptyArrayKey($_SERVER, $key) && strtolower($_SERVER[$key]) !== 'off';
307
}
308
309
/**
310
 * Get a QR code.
311
 *
312
 * @param string $string String to generate QR code for.
313
 * @param int $width QR code width
314
 * @param int $height QR code height
315
 * @param array $attributes Optional, additional key/value attributes to include in the IMG tag
316
 *
317
 * @return string containing complete image tag
318
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
319
 */
320
function getQRcode($string, int $width = 150, int $height = 150, array $attributes = []) : string
321
{
322
    $attr = arrayToString($attributes);
323
    $apiUrl = getQRcodeUrl($string, $width, $height);
324
    return '<img src="' . $apiUrl . '" ' . trim($attr) . ' />';
325
}
326
327
/**
328
 * Get a QR code Url.
329
 *
330
 * @param string $string String to generate QR code for.
331
 * @param int $width QR code width
332
 * @param int $height QR code height
333
 *
334
 * @return string containing complete image url
335
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
336
 */
337
function getQRcodeUrl($string, int $width = 150, int $height = 150) : string
338
{
339
    $protocol = 'http://';
340
    if (isHttps()) {
341
        $protocol = 'https://';
342
    }
343
    return $protocol . 'chart.apis.google.com/chart?chs=' . $width . 'x' . $height . '&cht=qr&chl=' . urlencode($string);
344
}
345
346
if (!function_exists('gravatarUrl')) {
347
    /**
348
     * Get a Gravatar URL from email.
349
     *
350
     * @param string $email The email address
351
     * @param int $size in pixels, defaults to 80px [ 1 - 2048 ]
352
     * @param string $default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
353
     * @param string $rating (inclusive) [ g | pg | r | x ]
354
     * @return string
355
     * @source http://gravatar.com/site/implement/images/php/
356
     */
357
    function gravatarUrl($email, $size = 80, $default = 'mm', $rating = 'g')
358
    {
359
        $url = 'https://www.gravatar.com';
360
        $url .= '/avatar/' . md5(strtolower(trim($email))) . '?default=' . $default . '&size=' . $size . '&rating=' . $rating;
361
        return $url;
362
    }
363
}
364
365
if (!function_exists('gravatar')) {
366
    /**
367
     * Get a Gravatar img tag from email.
368
     *
369
     * @param string $email The email address
370
     * @param int $size in pixels, defaults to 80px [ 1 - 2048 ]
371
     * @param string $default imageset to use [ 404 | mm | identicon | monsterid | wavatar ]
372
     * @param string $rating (inclusive) [ g | pg | r | x ]
373
     * @param array $attributes Optional, additional key/value attributes to include in the IMG tag
374
     * @return string
375
     * @source http://gravatar.com/site/implement/images/php/
376
     */
377
    function gravatar($email, $size = 80, $default = 'mm', $rating = 'g', $attributes = [])
378
    {
379
        $attr = arrayToString($attributes);
380
        $url = gravatarUrl($email, $size, $default, $rating);
381
        return '<img src="' . $url . '" width="' . $size . 'px" height="' . $size . 'px" ' . trim($attr) . ' />';
382
    }
383
}
384
385
if (!function_exists('isAjax')) {
386
387
    /**
388
     * Determine if current page request type is ajax.
389
     *
390
     * @return bool
391
     */
392
    function isAjax()
393
    {
394
        return isNotNullOrEmptyArrayKey($_SERVER, 'HTTP_X_REQUESTED_WITH')
395
        && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
396
    }
397
}
398
399
if (!function_exists('isNumberOdd')) {
400
401
    /**
402
     * Check if number is odd.
403
     *
404
     * @param int $num integer to check
405
     *
406
     * @return bool
407
     * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
408
     */
409
    function isNumberOdd($num)
410
    {
411
        return $num % 2 !== 0;
412
    }
413
}
414
415
if (!function_exists('isNumberEven')) {
416
417
    /**
418
     * Check if number is even.
419
     *
420
     * @param int $num integer to check
421
     *
422
     * @return bool
423
     * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
424
     */
425
    function isNumberEven($num)
426
    {
427
        return $num % 2 == 0;
428
    }
429
}
430
431
if (!function_exists('getCurrentUrlPageName')) {
432
433
    /**
434
     * Returns The Current URL PHP File Name.
435
     * Ex.: http://www.dummy.com/one/two/index.php?one=1&two=2 return index.php
436
     *
437
     * @return string
438
     */
439
    function getCurrentUrlPageName() : string
440
    {
441
        return isNotNullOrEmptyArrayKey($_SERVER, 'PHP_SELF') ? basename($_SERVER['PHP_SELF']) : '';
442
    }
443
}
444
445
if (!function_exists('getCurrentUrlQuerystring')) {
446
447
    /**
448
     * Returns The Current URL querystring.
449
     * Ex.: http://www.dummy.com/one/two/index.php?one=1&two=2 return one=1&two=2
450
     *
451
     * @return string
452
     */
453
    function getCurrentUrlQuerystring() : string
454
    {
455
        return isNotNullOrEmptyArrayKey($_SERVER, 'QUERY_STRING') ? $_SERVER['QUERY_STRING'] : '';
456
    }
457
}
458
459
if (!function_exists('getCurrentUrlDirName')) {
460
461
    /**
462
     * Returns The Current URL Path Name.
463
     * Ex.: http://www.dummy.com/one/two/index.php?one=1&two=2 return /one/two
464
     *
465
     * @return string
466
     */
467
    function getCurrentUrlDirName() : string
468
    {
469
        if (isNotNullOrEmptyArrayKey($_SERVER, 'REQUEST_URI')) {
470
            return dirname($_SERVER['REQUEST_URI']);
471
        }
472
        return isNotNullOrEmptyArrayKey($_SERVER, 'PHP_SELF') ? dirname($_SERVER['PHP_SELF']) : '';
473
    }
474
}
475
476
if (!function_exists('getCurrentUrlDirAbsName')) {
477
478
    /**
479
     * Returns The Current URL Absolute Path Name.
480
     * Ex.: http://www.dummy.com/one/two/index.php?one=1&two=2 return /home/user/www/one/two
481
     *
482
     * @return string
483
     */
484
    function getCurrentUrlDirAbsName() : string
485
    {
486
        return isNotNullOrEmptyArrayKey($_SERVER, 'SCRIPT_FILENAME') ? dirname($_SERVER['SCRIPT_FILENAME']) : '';
487
    }
488
}
489
490
if (!function_exists('getCurrentURL')) {
491
492
    /**
493
     * Return the current URL.
494
     * Ex.: http://www.dummy.com/one/two/index.php?one=1&two=2
495
     * Or
496
     * Ex.: https://username:[email protected]:443/one/two/index.php?one=1&two=2
497
     * @return string
498
     * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
499
     */
500
    function getCurrentURL()
501
    {
502
        $url = 'http://';
503
        if (isHttps()) {
504
            $url = 'https://';
505
        }
506
        if (array_key_exists_safe($_SERVER, 'PHP_AUTH_USER')) {
507
            $url .= $_SERVER['PHP_AUTH_USER'];
508
            if (array_key_exists_safe($_SERVER, 'PHP_AUTH_PW')) {
509
                $url .= ':' . $_SERVER['PHP_AUTH_PW'];
510
            }
511
            $url .= '@';
512
        }
513
        if (array_key_exists_safe($_SERVER, 'HTTP_HOST')) {
514
            $url .= $_SERVER['HTTP_HOST'];
515
        }
516
        if (array_key_exists_safe($_SERVER, 'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80) {
517
            $url .= ':' . $_SERVER['SERVER_PORT'];
518
        }
519
        if (!array_key_exists_safe($_SERVER, 'REQUEST_URI')) {
520
            $url .= substr($_SERVER['PHP_SELF'], 1);
521
            if (array_key_exists_safe($_SERVER, 'QUERY_STRING')):
522
                $url .= '?' . $_SERVER['QUERY_STRING'];
523
            endif;
524
        } else {
525
            $url .= $_SERVER['REQUEST_URI'];
526
        }
527
        return $url;
528
    }
529
}
530
531
if (!function_exists('isMobile')) {
532
533
    /**
534
     * Detect if user is on mobile device.
535
     *
536
     * @return bool
537
     */
538
    function isMobile()
539
    {
540
        $useragent = array_key_exists_safe($_SERVER, 'HTTP_USER_AGENT') ? $_SERVER['HTTP_USER_AGENT'] : '';
541
        if($useragent===''){
542
            return false;
543
        }
544
        return preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i',
545
            $useragent)
546
        || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',
547
            substr($useragent, 0, 4));
548
    }
549
}
550
551
/**
552
 * Get user browser.
553
 *
554
 * @return string
555
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
556
 */
557
function getBrowser()
558
{
559
    $u_agent = $_SERVER['HTTP_USER_AGENT'];
560
    $browserName = $ub = $platform = 'Unknown';
561
    if (preg_match('/linux/i', $u_agent)) {
562
        $platform = 'Linux';
563
    } elseif (preg_match('/macintosh|mac os x/i', $u_agent)) {
564
        $platform = 'Mac OS';
565
    } elseif (preg_match('/windows|win32/i', $u_agent)) {
566
        $platform = 'Windows';
567
    }
568
    if (preg_match('/MSIE/i', $u_agent) && !preg_match('/Opera/i', $u_agent)) {
569
        $browserName = 'Internet Explorer';
570
        $ub = 'MSIE';
571
    } elseif (preg_match('/Firefox/i', $u_agent)) {
572
        $browserName = 'Mozilla Firefox';
573
        $ub = 'Firefox';
574
    } elseif (preg_match('/Chrome/i', $u_agent)) {
575
        $browserName = 'Google Chrome';
576
        $ub = 'Chrome';
577
    } elseif (preg_match('/Safari/i', $u_agent)) {
578
        $browserName = 'Apple Safari';
579
        $ub = 'Safari';
580
    } elseif (preg_match('/Opera/i', $u_agent)) {
581
        $browserName = 'Opera';
582
        $ub = 'Opera';
583
    } elseif (preg_match('/Netscape/i', $u_agent)) {
584
        $browserName = 'Netscape';
585
        $ub = 'Netscape';
586
    }
587
    $known = ['Version', $ub, 'other'];
588
    $pattern = '#(?<browser>' . implode('|', $known) . ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
589
    preg_match_all($pattern, $u_agent, $matches);
590
    $i = count($matches['browser']);
591
    if ($i != 1) {
592
        if (strripos($u_agent, 'Version') < strripos($u_agent, $ub)) {
593
            $version = $matches['version'][0];
594
        } else {
595
            $version = $matches['version'][1];
596
        }
597
    } else {
598
        $version = $matches['version'][0];
599
    }
600
    if ($version == null || $version == '') {
601
        $version = '?';
602
    }
603
    return implode(', ', [$browserName, 'Version: ' . $version, $platform]);
604
}
605
606
/**
607
 * Shorten URL via tinyurl.com service.
608
 * It support http or https.
609
 * @param string $url URL to shorten
610
 *
611
 * @return string shortend url or empty string if it fails.
612
 */
613
function getTinyUrl(string $url) : string
614
{
615
    if (!starts_with($url, 'http')) {
616
        $url = (isHttps() ? 'https://' : 'http://') . $url;
617
    }
618
    $gettiny = curl('http://tinyurl.com/api-create.php?url=' . $url);
619
    if (isNullOrEmpty($gettiny) && isNullOrEmptyArray($gettiny)) {
620
        return '';
621
    }
622
    if (isHttps()) {
623
        $gettiny = str_replace('http://', 'https://', $gettiny);
624
    }
625
    return $gettiny;
626
}
627
628
/**
629
 * Get information on a short URL. Find out where it goes.
630
 *
631
 * @param string $shortURL shortened URL
632
 *
633
 * @return string full url or empty string
634
 * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
635
 */
636
function expandShortUrl(string $shortURL) : string
637
{
638
    if (isNullOrEmpty($shortURL)) {
639
        return '';
640
    }
641
    $headers = get_headers($shortURL, 1);
642
    if (array_key_exists_safe($headers, 'Location')) {
643
        return $headers['Location'];
644
    }
645
    $data = curl($shortURL);
646
    preg_match_all('/<[\s]*meta[\s]*http-equiv="?' . '([^>"]*)"?[\s]*' . 'content="?([^>"]*)"?[\s]*[\/]?[\s]*>/si',
647
        $data, $match);
648
    if (isNullOrEmptyArray($match) || count($match) != 3
649
        || isNullOrEmptyArray($match[0]) || isNullOrEmptyArray($match[1]) || isNullOrEmptyArray($match[2])
650
        || count($match[0]) != count($match[1]) || count($match[1]) != count($match[2])
651
    ) {
652
        return '';
653
    }
654
    $originals = $match[0];
655
    $names = $match[1];
656
    $values = $match[2];
657
    $metaTags = [];
658
    for ($i = 0, $limit = count($names); $i < $limit; $i++) {
659
        $metaTags[$names[$i]] = ['html' => htmlentities($originals[$i]), 'value' => $values[$i]];
660
    }
661
    if (!isset($metaTags['refresh']['value']) || empty($metaTags['refresh']['value'])) {
662
        return '';
663
    }
664
    $returnData = explode('=', $metaTags['refresh']['value']);
665
    if (!isset($returnData[1]) || empty($returnData[1])) {
666
        return '';
667
    }
668
    return $returnData[1];
669
}
670
671
if (!function_exists('curl')) {
672
673
    /**
674
     * Make Curl call.
675
     *
676
     * @param string $url URL to curl
677
     * @param string $method GET or POST, Default GET
678
     * @param mixed $data Data to post, Default false
679
     * @param string[] $headers Additional headers, example: array ("Accept: application/json")
680
     * @param bool $returnInfo Whether or not to retrieve curl_getinfo()
681
     * @param string $user
682
     * @param string $password
683
     * @param bool $sslNotVerifyHostAndPeer is set to true do not check SSL certificate.
684
     * @param bool $followLocation
685
     * @param int $timeout
686
     * @param string $logPath if not empty write log to this file
687
     * @param string $referer
688
     * @param string $userAgent default 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0'
689
     * and ignore $returnInfo (i.e. call curl_getinfo even if $returnInfo is set to false).
690
     *
691
     * @return string|array if $returnInfo is set to True, array is returned with two keys, contents (will contain response) and info (information regarding a specific transfer), otherwise response content is returned
692
     * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
693
     */
694
    function curl(
695
        $url,
696
        $method = 'GET',
697
        $data = false,
698
        array $headers = [],
699
        bool $returnInfo = false,
700
        string $user = '',
701
        string $password = '',
702
        bool $sslNotVerifyHostAndPeer = false,
703
        bool $followLocation = false,
704
        int $timeout = 10,
705
        string $logPath = '',
706
        string $referer = '',
707
        string $userAgent = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0'
708
    ) {
709
        $log = false;
710
        if (isNotNullOrEmpty($logPath)) {
711
            $log = true;
712
            $msg = "REQUEST_URI: " . (isNotNullOrEmptyArrayKey($_SERVER,
713
                    'REQUEST_URI') ? $_SERVER['REQUEST_URI'] : '') . "\r\n"
714
                . "SCRIPT_NAME: " . (isNotNullOrEmptyArrayKey($_SERVER,
715
                    'SCRIPT_NAME') ? $_SERVER['SCRIPT_NAME'] : '') . "\r\n"
716
                . "REMOTE ADDR: " . (isNotNullOrEmptyArrayKey($_SERVER,
717
                    'REMOTE_ADDR') ? $_SERVER['REMOTE_ADDR'] : '') . "\r\n"
718
                . "HTTP_HOST: " . (isNotNullOrEmptyArrayKey($_SERVER,
719
                    'HTTP_HOST') ? $_SERVER['HTTP_HOST'] : '') . "\r\n"
720
                . "SERVER_NAME: " . (isNotNullOrEmptyArrayKey($_SERVER,
721
                    'SERVER_NAME') ? $_SERVER['SERVER_NAME'] : '') . "\r\n"
722
                . "HTTP_X_FORWARDED_FOR: " . (isNotNullOrEmptyArrayKey($_SERVER,
723
                    'HTTP_X_FORWARDED_FOR') ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '') . "\r\n"
724
                . "SERVER_ADDR: " . (isNotNullOrEmptyArrayKey($_SERVER,
725
                    'SERVER_ADDR') ? $_SERVER['SERVER_ADDR'] : '') . "\r\n"
726
                . "REMOTE_PORT: " . (isNotNullOrEmptyArrayKey($_SERVER,
727
                    'REMOTE_PORT') ? $_SERVER['REMOTE_PORT'] : '') . "\r\n"
728
                . "HTTPS: " . (isNotNullOrEmptyArrayKey($_SERVER, 'HTTPS') ? $_SERVER['HTTPS'] : '') . "\r\n"
729
                . "HTTP_X_FORWARDED_PROTO: " . (isNotNullOrEmptyArrayKey($_SERVER,
730
                    'HTTP_X_FORWARDED_PROTO') ? $_SERVER['HTTP_X_FORWARDED_PROTO'] : '') . "\r\n"
731
                . "data: " . get_var_dump_output($data) . "\r\n"
732
                . "headers: " . get_var_dump_output($headers) . "\r\n"
733
                . "returnInfo: " . $returnInfo . "\r\n"
734
                . "url: " . $url . "\r\n"
735
                . "method: " . $method . "\r\n"
736
                . "user: " . $user . "\r\n"
737
                . "password: " . (strlen($password) > 2 ? substr($password, 0, 2) . str_repeat('x',
738
                        10) . substr($password, -1) : 'xx') . "\r\n"
739
                . "sslNotVerifyHostAndPeer: " . $sslNotVerifyHostAndPeer . "\r\n"
740
                . "followLocation: " . $followLocation . "\r\n"
741
                . "timeout: " . $timeout . "\r\n"
742
                . "logPath: " . $logPath . "\r\n"
743
                . "referer: " . $referer . "\r\n"
744
                . "userAgent: " . $userAgent . "\r\n"
745
                . "\r\n";
746
            logToFile($logPath, $msg);
747
        }
748
        if (!function_exists('curl_init') || isNullOrEmpty($url)) {
749
            if ($log) {
750
                logToFile($logPath,
751
                    isNullOrEmpty($url) ? 'url is empty.curl abort.' : 'curl_init not exists.Probabily CURL is not installed.');
752
            }
753
            return '';
754
        }
755
        $ch = curl_init();
756
        $info = null;
757
        if (strtoupper($method) == 'POST') {
758
            curl_setopt($ch, CURLOPT_POST, true);
759
            if ($data !== false) {
760
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
761
            }
762
        } elseif ($data !== false) {
763
            if (is_array($data)) {
764
                $dataTokens = [];
765
                foreach ($data as $key => $value) {
766
                    $dataTokens[] = urlencode($key) . '=' . urlencode($value);
767
                }
768
                $data = implode('&', $dataTokens);
769
            }
770
            $url .= (strpos($url, '?') === false ? '?' : '&') . $data;
771
        }
772
        curl_setopt($ch, CURLOPT_URL, $url);
773
        curl_setopt($ch, CURLOPT_HEADER, false);
774
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
775
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $followLocation ? true : false);
776
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout <= 1 ? 10 : $timeout);
777
        if ($sslNotVerifyHostAndPeer && starts_with($url, 'https://')) {
778
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
779
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
780
        }
781
        if (isNotNullOrEmptyArray($headers)) {
782
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
783
        }
784
        if (isNotNullOrEmpty($user) && isNotNullOrEmpty($password)) {
785
            curl_setopt($ch, CURLOPT_USERPWD, $user . ':' . $password);
786
        }
787
        if (isNotNullOrEmpty($referer)) {
788
            curl_setopt($ch, CURLOPT_REFERER, $referer);
789
        }
790
        if (isNotNullOrEmpty($userAgent)) {
791
            curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
792
        }
793
794
        if ($log) {
795
            logToFile($logPath, date('Y-m-d H:i:s') . "Start curl\r\n");
796
        }
797
        $contents = curl_exec($ch);
798
        if ($log) {
799
            logToFile($logPath, date('Y-m-d H:i:s') . "FINISH curl\r\n");
800
        }
801
802
        if ($returnInfo || $log || $contents === false || curl_errno($ch) > 0) {
803
            $info = curl_getinfo($ch);
804
            if ($log) {
805
                logToFile($logPath, $info, true);
806
            }
807
        }
808
809
        if ($contents === false || curl_errno($ch) > 0
810
            || !array_key_exists_safe($info === null ? [] : $info, 'http_code') || $info['http_code'] != 200
811
        ) {
812
            if ($log) {
813
                logToFile($logPath, "Error during exec CURL \r\n curl_error: " . curl_error($ch)
814
                    . "\r\n curl_errno: " . curl_errno($ch) . "\r\n");
815
            }
816
        } elseif ($log) {
817
            logToFile($logPath, "CURL IS OK\r\n RESPONSE: \r\n" . $contents);
818
        }
819
820
        curl_close($ch);
821
        return ($returnInfo ? ['contents' => $contents, 'info' => $info] : $contents);
822
    }
823
}
824
825
826
if (!function_exists('curl_internal_server_behind_load_balancer')) {
827
828
    /**
829
     * Make Curl call to one of the server behinds load balancer.
830
     *
831
     * @param string $url URL to curl
832
     * @param string $server_name The host name of the domain from the call will start.
833
     * if empty try to resolve from SERVER_NAME
834
     * @param string $localServerIpAddress the IP of one server to call that behinds load balancer.
835
     * if empty try to resolve from SERVER_ADDR
836
     * @param string $method GET or POST, Default GET
837
     * @param mixed $data Data to post, Default false
838
     * @param array $headers Additional headers, example: array ("Accept: application/json")
839
     * @param bool $returnInfo Whether or not to retrieve curl_getinfo()
840
     * @param string $user
841
     * @param string $password
842
     * @param bool $sslNotVerifyHostAndPeer is set to true do not check SSL certificate.
843
     * @param bool $followLocation
844
     * @param int $timeout
845
     * @param string $logPath if not empty write log to this file
846
     * @param string $referer
847
     * @param string $userAgent default 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0'
848
     * and ignore $returnInfo (i.e. call curl_getinfo even if $returnInfo is set to false).
849
     *
850
     * @return string|array if $returnInfo is set to True, array is returned with two keys, contents (will contain response) and info (information regarding a specific transfer), otherwise response content is returned
851
     */
852
    function curl_internal_server_behind_load_balancer(
853
        $url,
854
        $server_name = '',
855
        $localServerIpAddress = '',
856
        $method = 'GET',
857
        $data = false,
858
        array $headers = [],
859
        bool $returnInfo = false,
860
        string $user = '',
861
        string $password = '',
862
        bool $sslNotVerifyHostAndPeer = false,
863
        bool $followLocation = false,
864
        int $timeout = 10,
865
        string $logPath = '',
866
        string $referer = '',
867
        string $userAgent = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0'
868
    ) {
869
        if (isNullOrEmpty($server_name) && isNotNullOrEmptyArrayKey($_SERVER, 'SERVER_NAME')) {
870
            $server_name = $_SERVER['SERVER_NAME'];
871
        }
872
873 View Code Duplication
        if (isNullOrEmpty($server_name) && isNotNullOrEmpty($logPath)) {
874
            $msg = 'No server name given for calling curl ' . $url . ' behind proxy or LB';
875
            logToFile($logPath, $msg);
876
            return false;
877
        }
878
879
        if (isNullOrEmpty($localServerIpAddress) && isNotNullOrEmptyArrayKey($_SERVER, 'SERVER_ADDR')) {
880
            $localServerIpAddress = $_SERVER['SERVER_ADDR'];
881
        }
882
883 View Code Duplication
        if (isNullOrEmpty($localServerIpAddress) && isNotNullOrEmpty($logPath)) {
884
            $msg = 'No localIPAddress given for calling curl ' . $url . ' behind proxy or LB';
885
            logToFile($logPath, $msg);
886
            return false;
887
        }
888
889
        $url = str_replace($server_name, $localServerIpAddress, $url);
890
891
        //Using the host header to bypass a load balancer
892
        if (!is_array($headers)) {
893
            $headers = array();
894
        }
895
        $headers[] = 'Host: ' . $server_name;
896
897
        return curl($url, $method, $data, $headers, $returnInfo, $user, $password, $sslNotVerifyHostAndPeer,
898
            $followLocation, $timeout, $logPath, $referer, $userAgent);
899
    }
900
}
901
902
if (!function_exists('startLayoutCapture')) {
903
904
    /**
905
     * Turn On the output buffering.
906
     * @return bool
907
     */
908
    function startLayoutCapture() : bool
909
    {
910
        return ob_start();
911
    }
912
}
913
914
if (!function_exists('endLayoutCapture')) {
915
916
    /**
917
     * Get the buffer contents for the topmost buffer and clean it.
918
     * @return string
919
     */
920
    function endLayoutCapture() : string
921
    {
922
        $data = ob_get_contents();
923
        ob_end_clean();
924
        return $data === false ? '' : $data;
925
    }
926
}
927
928
if (!function_exists('get_var_dump_output')) {
929
930
    /**
931
     * Capture var dump $var output and return it.
932
     * @param $var
933
     * @return string
934
     */
935
    function get_var_dump_output($var)
936
    {
937
        startLayoutCapture();
938
        $myfunc = "var_dump";
939
        $myfunc($var);
940
        return endLayoutCapture();
941
    }
942
}
943
944
if (!function_exists('debug')) {
945
946
    /**
947
     * Dump information about a variable.
948
     *
949
     * @param mixed $variable Variable to debug
950
     *
951
     * @return void
952
     * @see https://github.com/ngfw/Recipe/blob/master/src/ngfw/Recipe.php
953
     */
954
    function debug($variable)
955
    {
956
        $output = get_var_dump_output($variable);
957
        $maps = [
958
            'string' => "/(string\((?P<length>\d+)\)) (?P<value>\"(?<!\\\).*\")/i",
959
            'array' => "/\[\"(?P<key>.+)\"(?:\:\"(?P<class>[a-z0-9_\\\]+)\")?(?:\:(?P<scope>public|protected|private))?\]=>/Ui",
960
            'countable' => "/(?P<type>array|int|string)\((?P<count>\d+)\)/",
961
            'resource' => "/resource\((?P<count>\d+)\) of type \((?P<class>[a-z0-9_\\\]+)\)/",
962
            'bool' => "/bool\((?P<value>true|false)\)/",
963
            'float' => "/float\((?P<value>[0-9\.]+)\)/",
964
            'object' => "/object\((?P<class>\S+)\)\#(?P<id>\d+) \((?P<count>\d+)\)/i"
965
        ];
966
        foreach ($maps as $function => $pattern) {
967
            $output = preg_replace_callback($pattern, function ($matches) use ($function) {
968
                switch ($function) {
969
                    case 'string':
970
                        $matches['value'] = htmlspecialchars($matches['value']);
971
                        return '<span style="color: #0000FF;">string</span>(<span style="color: #1287DB;">' . $matches['length'] . ')</span> <span style="color: #6B6E6E;">' . $matches['value'] . '</span>';
972
                    case 'array':
973
                        $key = '<span style="color: #008000;">"' . $matches['key'] . '"</span>';
974
                        $class = '';
975
                        $scope = '';
976
                        if (isset($matches['class']) && !empty($matches['class'])) {
977
                            $class = ':<span style="color: #4D5D94;">"' . $matches['class'] . '"</span>';
978
                        }
979
                        if (isset($matches['scope']) && !empty($matches['scope'])) {
980
                            $scope = ':<span style="color: #666666;">' . $matches['scope'] . '</span>';
981
                        }
982
                        return '[' . $key . $class . $scope . ']=>';
983
                    case 'countable':
984
                        $type = '<span style="color: #0000FF;">' . $matches['type'] . '</span>';
985
                        $count = '(<span style="color: #1287DB;">' . $matches['count'] . '</span>)';
986
                        return $type . $count;
987
                    case 'bool':
988
                        return '<span style="color: #0000FF;">bool</span>(<span style="color: #0000FF;">' . $matches['value'] . '</span>)';
989
                    case 'float':
990
                        return '<span style="color: #0000FF;">float</span>(<span style="color: #1287DB;">' . $matches['value'] . '</span>)';
991
                    case 'resource':
992
                        return '<span style="color: #0000FF;">resource</span>(<span style="color: #1287DB;">' . $matches['count'] . '</span>) of type (<span style="color: #4D5D94;">' . $matches['class'] . '</span>)';
993
                    case 'object':
994
                        return '<span style="color: #0000FF;">object</span>(<span style="color: #4D5D94;">' . $matches['class'] . '</span>)#' . $matches['id'] . ' (<span style="color: #1287DB;">' . $matches['count'] . '</span>)';
995
                }
996
            }, $output);
997
        }
998
        $header = '';
999
        list($debugfile) = debug_backtrace();
1000
        if (!empty($debugfile['file'])) {
1001
            $header = '<h4 style="border-bottom:1px solid #bbb;font-weight:bold;margin:0 0 10px 0;padding:3px 0 10px 0">' . $debugfile['file'] . '</h4>';
1002
        }
1003
        echo '<pre style="background-color: #CDDCF4;border: 1px solid #bbb;border-radius: 4px;-moz-border-radius:4px;-webkit-border-radius\:4px;font-size:12px;line-height:1.4em;margin:30px;padding:7px">' . $header . $output . '</pre>';
1004
    }
1005
}
1006
1007
if (!function_exists('getReferer')) {
1008
1009
    /**
1010
     * Return referer page if exists otherwise return empty string.
1011
     *
1012
     * @return string
1013
     */
1014
    function getReferer() : string
1015
    {
1016
        return isNotNullOrEmptyArrayKey($_SERVER, 'HTTP_REFERER') ? $_SERVER['HTTP_REFERER'] : '';
1017
    }
1018
}
1019
1020
if (!function_exists('isZlibOutputCompressionActive')) {
1021
1022
    /**
1023
     * Check if zlib output compression was active
1024
     * @return bool
1025
     */
1026
    function isZlibOutputCompressionActive() : bool
1027
    {
1028
        return ini_get('zlib.output_compression') == 'On'
1029
        || ini_get('zlib.output_compression_level') > 0
1030
        || ini_get('output_handler') == 'ob_gzhandler';
1031
    }
1032
}
1033
1034
if (!function_exists('isZlibLoaded')) {
1035
1036
    /**
1037
     * Check if zlib extension was loaded
1038
     * @return bool
1039
     */
1040
    function isZlibLoaded() : bool
1041
    {
1042
        return extension_loaded('zlib');
1043
    }
1044
}
1045
1046
if (!function_exists('isClientAcceptGzipEncoding')) {
1047
1048
    /**
1049
     * Check if client accept gzip encoding
1050
     * @return bool
1051
     */
1052
    function isClientAcceptGzipEncoding() : bool
1053
    {
1054
        return isNotNullOrEmptyArrayKey($_SERVER, 'HTTP_ACCEPT_ENCODING')
1055
        && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;
1056
    }
1057
}
1058
1059
if (!function_exists('compressHtmlPage')) {
1060
1061
    /**
1062
     * Captures output via ob_get_contents(), tries to enable gzip,
1063
     * removes whitespace from captured output and echos back
1064
     *
1065
     * @return string whitespace stripped output
1066
     * @see https://github.com/ngfw/Recipe/
1067
     */
1068
    function compressHtmlPage() : string
1069
    {
1070
        register_shutdown_function(function () {
1071
            $buffer = str_html_compress(ob_get_contents());
1072
            ob_end_clean();
1073
            if (!isZlibOutputCompressionActive() &&
1074
                isClientAcceptGzipEncoding() &&
1075
                isZlibLoaded()
1076
            ) {
1077
                ob_start('ob_gzhandler');
1078
            }
1079
            echo $buffer;
1080
        });
1081
    }
1082
}
1083
1084
if (!function_exists('get_http_response_code')) {
1085
1086
    /**
1087
     * @param string $theURL
1088
     * @param bool $useGet if set to true use a GET request, otherwise use a HEAD request (more fast).
1089
     * @return int return the http status or 999 if it fails.
1090
     */
1091
    function get_http_response_code(string $theURL, bool $useGet = false) : int
1092
    {
1093
        if (isNullOrEmpty($theURL)) {
1094
            return 999;
1095
        }
1096
        if (!$useGet) {
1097
            // By default get_headers uses a GET request to fetch the headers. If you
1098
            // want to send a HEAD request instead, you can do so using a stream context:
1099
            stream_context_set_default(
1100
                array(
1101
                    'http' => array(
1102
                        'method' => 'HEAD'
1103
                    )
1104
                )
1105
            );
1106
        }
1107
        $headers = @get_headers($theURL);
1108
1109
        if ($headers === false || isNullOrEmptyArray($headers) || strlen($headers[0]) < 12) {
1110
            return 999;
1111
        }
1112
        $status = substr($headers[0], 9, 3);
1113
        return isInteger($status) ? $status : 999;
1114
    }
1115
}
1116
1117
if (!function_exists('url_exists')) {
1118
1119
    /**
1120
     * Check if URL exists (return http status code <400
1121
     * @param string $url
1122
     * @return bool
1123
     */
1124
    function url_exists(string $url) : bool
1125
    {
1126
        return get_http_response_code($url) < 400;
1127
    }
1128
}
1129
1130
if (!function_exists('logToFile')) {
1131
1132
    /**
1133
     * Log variable into log file.
1134
     * @param string $pathFile full path with file name.
1135
     * @param mixed $value value to log
1136
     * @param bool $varDump default false. if set to true,
1137
     * grab var dump output of $value and write it to log, otherwise append it to log.
1138
     */
1139
    function logToFile(string $pathFile, $value, bool $varDump = false)
1140
    {
1141
        if ($varDump) {
1142
            $value = get_var_dump_output($value);
1143
        }
1144
        $f = fopen($pathFile, 'ab');
1145
        fwrite($f, date(DATE_RFC822) . "\r\n" . $value . "\r\n----------------------------------------------\r\n");
1146
        fclose($f);
1147
    }
1148
}
1149
1150
/**
1151
 * Check if an extension is an image type.
1152
 * @param  string $ext extension to check
1153
 * @return boolean
1154
 * @see https://github.com/kohana/ohanzee-helpers/blob/master/src/Mime.php
1155
 */
1156
function isImageExtension(string $ext) : bool
1157
{
1158
    return in_array(strtolower($ext), getImageExtensions());
1159
}
1160
1161
/**
1162
 * Get a list of common image extensions. Only types that can be read by
1163
 * PHP's internal image methods are included!
1164
 * @return string[]
1165
 */
1166
function getImageExtensions() : array
1167
{
1168
    return [
1169
        'bmp',
1170
        'gif',
1171
        'jpeg',
1172
        'jpg',
1173
        'png',
1174
        'tif',
1175
        'tiff',
1176
        'swf',
1177
    ];
1178
}
1179
1180
/**
1181
 * Very simple 'template' parser. Replaces (for example) {name} with the value of $vars['name'] in strings
1182
 *
1183
 * @param        $str
1184
 * @param array $vars
1185
 * @param string $openDelimiter
1186
 * @param string $closeDelimiter
1187
 *
1188
 * @return string
1189
 * @see https://github.com/laradic/support/blob/master/src/Util.php
1190
 * @example
1191
 * <?php
1192
 * $result = template('This is the best template parser. Created by {developerName}', ['developerName' => 'Radic']);
1193
 * echo $result; // This is the best template parser. Created by Radic
1194
 */
1195
function template($str, array $vars = [], $openDelimiter = '{', $closeDelimiter = '}')
1196
{
1197
    foreach ($vars as $k => $var) {
1198
        if (is_array($var)) {
1199
            $str = template($str, $var);
1200
        } elseif (is_string($var)) {
1201
            $str = str_replace($openDelimiter . $k . $closeDelimiter, $var, $str);
1202
        }
1203
    }
1204
    return $str;
1205
}
1206
1207
/**
1208
 * @param int $percent
1209
 * @return bool
1210
 * @see https://github.com/laradic/support/blob/master/src/Util.php
1211
 */
1212
function randomChance(int $percent = 50) : bool
1213
{
1214
    return random_int(0, 100) > 100 - $percent;
1215
}
1216
1217
/**
1218
 * @param Throwable $exception
1219
 * @return string
1220
 */
1221
function getExceptionTraceAsString(\Throwable $exception)
1222
{
1223
    $rtn = "";
1224
    $count = 0;
1225
    foreach ($exception->getTrace() as $frame) {
1226
        $args = "";
1227
        if (isset($frame['args'])) {
1228
            $args = [];
1229
            foreach ($frame['args'] as $arg) {
1230
                if (is_string($arg)) {
1231
                    $args[] = "'" . $arg . "'";
1232
                } elseif (is_array($arg)) {
1233
                    $args[] = "Array";
1234
                } elseif (is_null($arg)) {
1235
                    $args[] = 'NULL';
1236
                } elseif (is_bool($arg)) {
1237
                    $args[] = ($arg) ? "true" : "false";
1238
                } elseif (is_object($arg)) {
1239
                    $args[] = get_class($arg);
1240
                } elseif (is_resource($arg)) {
1241
                    $args[] = get_resource_type($arg);
1242
                } else {
1243
                    $args[] = $arg;
1244
                }
1245
            }
1246
            $args = implode(", ", $args);
1247
        }
1248
        $rtn .= sprintf("#%s %s(%s): %s(%s)\n",
1249
            $count,
1250
            isset($frame['file']) ? $frame['file'] : '',
1251
            isset($frame['line']) ? $frame['line'] : '',
1252
            $frame['function'],
1253
            $args);
1254
        $count++;
1255
    }
1256
    return $rtn;
1257
}
1258
1259
if (!function_exists('windows_os')) {
1260
    /**
1261
     * Determine whether the current environment is Windows based.
1262
     *
1263
     * @return bool
1264
     *
1265
     * @see https://github.com/illuminate/support/blob/master/helpers.php
1266
     */
1267
    function windows_os() : bool
1268
    {
1269
        return strtolower(substr(PHP_OS, 0, 3)) === 'win';
1270
    }
1271
}
1272
1273
if (!function_exists('getConsoleColorTagForStatusCode')) {
1274
    /**
1275
     * Get the color tag for the given status code to be use in symfony/laravel console.
1276
     *
1277
     * @param string $code
1278
     *
1279
     * @return string
1280
     *
1281
     * @see https://github.com/spatie/http-status-check/blob/master/src/CrawlLogger.php#L96
1282
     */
1283
    function getConsoleColorTagForStatusCode($code)
1284
    {
1285
        if (starts_with($code, '2')) {
1286
            return 'info';
1287
        }
1288
        if (starts_with($code, '3')) {
1289
            return 'comment';
1290
        }
1291
        return 'error';
1292
    }
1293
}
1294
1295
if (!function_exists('is_32bit')) {
1296
    /**
1297
     * Check if the OS architecture is 32bit.
1298
     *
1299
     * @return bool
1300
     *
1301
     * @see http://stackoverflow.com/questions/6303241/find-windows-32-or-64-bit-using-php
1302
     */
1303
    function is_32bit() : bool
1304
    {
1305
        return get_os_architecture()==32;
1306
    }
1307
}
1308
1309
if (!function_exists('is_64bit')) {
1310
    /**
1311
     * Check if the OS architecture is 64bit.
1312
     *
1313
     * @return bool
1314
     *
1315
     * @see http://stackoverflow.com/questions/6303241/find-windows-32-or-64-bit-using-php
1316
     */
1317
    function is_64bit() : bool
1318
    {
1319
        return get_os_architecture()==64;
1320
    }
1321
}
1322
1323
if (!function_exists('get_os_architecture')) {
1324
    /**
1325
     * Get the OS architecture 32 or 64 bit.
1326
     *
1327
     * @return int return 32 or 64 if ok, otherwise return 0.
1328
     *
1329
     * @see http://stackoverflow.com/questions/6303241/find-windows-32-or-64-bit-using-php
1330
     */
1331
    function get_os_architecture() : int
1332
    {
1333
        switch(PHP_INT_SIZE) {
1334
            case 4:
1335
                return 32;
1336
            case 8:
1337
                return 64;
1338
            default:
1339
                return 0;
1340
        }
1341
    }
1342
}
1343
1344
1345
if (!function_exists('isRequestFromCloudFlare')) {
1346
1347
    /**
1348
     * Check if request (by given $_SERVER) is a cloudflare request
1349
     * @param $server
1350
     * @return bool
1351
     */
1352
    function isRequestFromCloudFlare(array $server) : bool
1353
    {
1354
        if (!isset($server['HTTP_CF_CONNECTING_IP']) || !isIP($server['HTTP_CF_CONNECTING_IP'])) {
1355
            return false;
1356
        }
1357
1358
        if (isCloudFlareIp($server['REMOTE_ADDR'])) {
1359
            return true;
1360
        }
1361
1362
        //in case proxy or load balancer in front the server web
1363
        //the chained passed IPs are in the HTTP_X_FORWARDED_FOR var in these two possible ways:
1364
        //2.38.87.88
1365
        //2.38.87.88, 188.114.101.5
1366
        if (empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
1367
            return false;
1368
        }
1369
1370
        if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') === false) {
1371
            return isCloudFlareIp($server['HTTP_X_FORWARDED_FOR']);
1372
        }
1373
1374
        $IPs = explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']);
1375
        if (empty($IPs) || !is_array($IPs) || count($IPs) < 1) {
1376
            return false;
1377
        }
1378
1379
        //usually the cloudflare ip are the last IP in the stack, so start loop by last entries
1380
        for ($i = count($IPs) - 1; $i >= 0; $i--) {
1381
            $ip = trim($IPs[$i]);
1382
            if (isCloudFlareIp($ip)) {
1383
                return true;
1384
            }
1385
        }
1386
1387
        return false;
1388
    }
1389
}
1390
1391
if (!function_exists('isCloudFlareIp')) {
1392
1393
    /**
1394
     * Check if given ip is a valid cloudflare ip.
1395
     * @param $ip
1396
     * @return bool
1397
     */
1398
    function isCloudFlareIp($ip) : bool
1399
    {
1400
        if (!isIP($ip)) {
1401
            return false;
1402
        }
1403
1404
        //array given from https://www.cloudflare.com/ips-v4
1405
        $cf_ip_ranges = array(
1406
            '103.21.244.0/22',
1407
            '103.22.200.0/22',
1408
            '103.31.4.0/22',
1409
            '104.16.0.0/12',
1410
            '108.162.192.0/18',
1411
            '131.0.72.0/22',
1412
            '141.101.64.0/18',
1413
            '162.158.0.0/15',
1414
            '172.64.0.0/13',
1415
            '173.245.48.0/20',
1416
            '188.114.96.0/20',
1417
            '190.93.240.0/20',
1418
            '197.234.240.0/22',
1419
            '198.41.128.0/17',
1420
        );
1421
1422
        foreach ($cf_ip_ranges as $range) {
1423
            if (ipInRange($ip, $range)) {
1424
                return true;
1425
            }
1426
        }
1427
1428
        return false;
1429
    }
1430
}
1431
1432
if (!function_exists('gzCompressFile')) {
1433
1434
    /**
1435
     * GZIPs a file on disk (appending .gz to the name)
1436
     *
1437
     * From http://stackoverflow.com/questions/6073397/how-do-you-create-a-gz-file-using-php
1438
     * Based on function by Kioob at:
1439
     * http://www.php.net/manual/en/function.gzwrite.php#34955
1440
     *
1441
     * @param string $source Path to file that should be compressed
1442
     * @param integer $level GZIP compression level (default: 9)
1443
     * @return string New filename (with .gz appended) if success, or false if operation fails
1444
     */
1445
    function gzCompressFile($source, $level = 9)
1446
    {
1447
        $dest = $source . '.gz';
1448
        $mode = 'wb' . $level;
1449
        $error = false;
1450
        if ($fp_out = gzopen($dest, $mode)) {
1451
            if ($fp_in = fopen($source, 'rb')) {
1452
                while (!feof($fp_in))
1453
                    gzwrite($fp_out, fread($fp_in, 1024 * 512));
1454
                fclose($fp_in);
1455
            } else {
1456
                $error = true;
1457
            }
1458
            gzclose($fp_out);
1459
        } else {
1460
            $error = true;
1461
        }
1462
        if ($error)
1463
            return false;
1464
        else
1465
            return $dest;
1466
    }
1467
}
1468
1469
if (!function_exists('getFileMimeTypeByFileInfo')) {
1470
1471
    /**
1472
     * get File MimeType string using the newer PHP finfo functions.
1473
     *
1474
     * It tries to use the newer PHP finfo functions.
1475
     *
1476
     * @param string $filePath the full path file name
1477
     * @return mixed|string the mime type string or FALSE if it fails.
1478
     */
1479
    function getFileMimeTypeByFileInfo(string $filePath)
1480
    {
1481
        if (function_exists('finfo_file')) {
1482
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
1483
            $type = finfo_file($finfo, $filePath);
1484
            finfo_close($finfo);
1485
            return $type;
1486
        }
1487
1488
        return false;
1489
    }
1490
}
1491
1492
if (!function_exists('getFileMimeTypeByOSFileCommand')) {
1493
1494
    /**
1495
     * get File MimeType string using the OS' file command.
1496
     * AFAIK that's only available on *NIX systems,
1497
     *
1498
     * @param string $filePath the full path file name
1499
     * @return mixed|string the mime type string or FALSE if it fails.
1500
     */
1501
    function getFileMimeTypeByOSFileCommand(string $filePath)
1502
    {
1503
        if (windows_os()) {
1504
            return false;
1505
        }
1506
1507
        try{
1508
            $secondOpinion = exec('file -b --mime-type ' . escapeshellarg($filePath), $foo, $returnCode);
1509
            if ($returnCode === 0 && $secondOpinion) {
1510
                $type = $secondOpinion;
1511
                return $type;
1512
            }
1513
        }catch(Exception $exception){
1514
            return false;
1515
        }
1516
1517
        return false;
1518
    }
1519
}
1520
1521
if (!function_exists('getImageMimeTypeByExif_imagetype')) {
1522
1523
    /**
1524
     * get image MimeType string of image using exif_imagetype
1525
     *
1526
     * @param string $filePath the full path file name
1527
     * @return mixed|string the mime type string or FALSE if it fails.
1528
     */
1529
    function getImageMimeTypeByExif_imagetype(string $filePath)
1530
    {
1531
        try {
1532
            $exifImageType = exif_imagetype($filePath);
1533
            if ($exifImageType !== false) {
1534
                return image_type_to_mime_type($exifImageType);
1535
            }
1536
        }catch(Exception $exception){
1537
            return false;
1538
        }
1539
1540
        return false;
1541
    }
1542
}
1543
1544
if (!function_exists('getFileMimeType')) {
1545
1546
    /**
1547
     * get File MimeType string using more strategies.
1548
     *
1549
     * It tries to use the newer PHP finfo functions.
1550
     * If those aren't available, it uses the mime_content_type.
1551
     * If those didn't return anything useful, it'll try the OS' file command.
1552
     * AFAIK that's only available on *NIX systems,
1553
     * If nothing worked, it tries exif_imagetype as fallback for images only.
1554
     *
1555
     * @param string $filePath the full path file name
1556
     * @return mixed|string the mime type string or FALSE if it fails.
1557
     *
1558
     * See: https://stackoverflow.com/questions/1232769/how-to-get-the-content-type-of-a-file-in-php?noredirect=1&lq=1
1559
     *
1560
     */
1561
    function getFileMimeType(string $filePath)
1562
    {
1563
        //tries to use the newer PHP finfo functions
1564
        $type = getFileMimeTypeByFileInfo($filePath);
1565
1566
        //If those aren't available, it uses the mime_content_type.
1567
        if (!$type && function_exists('mime_content_type')) {
1568
            $type = mime_content_type($filePath);
1569
        }
1570
1571
        //If those didn't return anything useful, it'll try the OS' file command. AFAIK that's only available on *NIX systems,
1572
        if (!$type && in_array($type, array('application/octet-stream', 'text/plain'))) {
1573
            $type = getFileMimeTypeByOSFileCommand($filePath);
1574
        }
1575
1576
        //If nothing worked, it tries exif_imagetype as fallback for images only.
1577
        if (!$type && in_array($type, array('application/octet-stream', 'text/plain'))) {
1578
            $type = getImageMimeTypeByExif_imagetype($filePath);
1579
        }
1580
1581
        return $type;
1582
    }
1583
}
1584