helpers.php ➔ curl()   F
last analyzed

Complexity

Conditions 47
Paths > 20000

Size

Total Lines 129

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 47
nc 44065794
nop 13
dl 0
loc 129
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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