Issues (994)

src/MVC/helper.php (19 issues)

1
<?php
2
3
namespace MVC;
4
5
setlocale(LC_ALL, 'en_US.UTF-8');
6
if (!defined('ROOT')) {
7
  define('ROOT', realpath(__DIR__ . '/../../'));
8
}
9
10
class helper
11
{
12
  public static $key = 'AUX';
13
  public static $expire = 10;
14
  public static $router;
15
  /**
16
   * Class architecture database.
17
   *
18
   * @var array
19
   */
20
  public static $arch = [];
21
22
  public function __construct()
23
  {
24
    if (!isset($_SERVER['HTTP_USER_AGENT']) || false !== stripos(strtolower($_SERVER['HTTP_USER_AGENT']), 'curl')) {
25
      http_response_code(403);
26
      if (ob_get_level()) {
27
        ob_end_clean();
28
      }
29
      include __DIR__ . '/themes/robot/index.php';
30
      exit;
0 ignored issues
show
Using exit here is not recommended.

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

Loading history...
31
    }
32
    if (isset($_REQUEST['cache'])) {
33
      self::$key .= $_REQUEST['cache'];
34
    }
35
    if (!self::$router) {
36
      self::$router = new router();
37
    }
38
  }
39
40
  /**
41
   * ```php
42
   * if (env('dev')) return boolean; //is development environtment or not
43
   * ```
44
   * Get environtment framework.
45
   *
46
   * @param string $for dev or prod
47
   *
48
   * @return string|bool
49
   */
50
  public static function env($for)
51
  {
52
    if (!self::$router) {
53
      self::$router = new router();
54
    }
55
56
    if ('dev' == $for || 'development' == $for) {
57
      return 'development' == self::$router->get_env();
58
    } elseif ('prod' == $for || 'production' == $for) {
59
      return 'production' == self::$router->get_env();
60
    } else {
61
      return self::$router->get_env();
62
    }
63
  }
64
65
  public static function config()
66
  {
67
    return \Filemanager\file::get(ROOT . '/config.json', true);
68
  }
69
70
  /**
71
   * Get Header Request Accept.
72
   *
73
   * @return void
74
   */
75
  public static function HeaderAccept()
76
  {
77
    if (isset($_SERVER['HTTP_ACCEPT']) && $accept = $_SERVER['HTTP_ACCEPT']) {
78
      switch ($accept) {
79
        case '*/*':
80
          return 'any';
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'any' returns the type string which is incompatible with the documented return type void.
Loading history...
81
          break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
82
        case 'application/javascript':
83
          return 'javascript';
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'javascript' returns the type string which is incompatible with the documented return type void.
Loading history...
84
          break;
85
        case 'application/json':
86
          return 'json';
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'json' returns the type string which is incompatible with the documented return type void.
Loading history...
87
          break;
88
          /*case strpos($accept, 'application/json') >= 0:
89
          return 'has_json';
90
          break;
91
        case strpos($accept, 'application/javascript') >= 0:
92
          return 'has_javascript';
93
          break;*/
94
        default:
95
          return $accept;
96
          break;
97
      }
98
    }
99
  }
100
101
  /**
102
   * Clean output buffers.
103
   *
104
   * @return void
105
   */
106
  public static function cleanBuffer()
107
  {
108
    if (ob_get_level()) {
109
      ob_end_clean();
110
      ob_start();
111
    }
112
  }
113
114
  public static function require_method(string $method)
115
  {
116
    $method = strtoupper($method);
117
    if ($method != $_SERVER['REQUEST_METHOD']) {
118
      throw new Exception("Request only accept $method request", 1);
119
    }
120
  }
121
122
  /**
123
   * is url ?
124
   *
125
   * @param string $url
126
   *
127
   * @return bool
128
   */
129
  public static function is_url($url)
130
  {
131
    return filter_var($url, FILTER_VALIDATE_URL);
132
  }
133
134
  /**
135
   * transfor url to host (domain only).
136
   *
137
   * @param mixed $fallback if url is not valid return $fallback value
138
   *
139
   * @return string|null
140
   */
141
  public static function url2host(string $url, $fallback = null)
142
  {
143
    if (
144
      isset(self::$arch[__FUNCTION__][md5($url)]) &&
145
      !empty(self::$arch[__FUNCTION__][md5($url)])
146
    ) {
147
      return self::$arch[__FUNCTION__][md5($url)];
148
    }
149
    if (self::is_url($url)) {
150
      $parse = self::parse_url2($url);
151
      if (isset($parse['host'])) {
152
        self::$arch[__FUNCTION__][md5($url)] = $parse['host'];
153
154
        return $parse['host'];
155
      }
156
    }
157
158
    return $fallback;
159
  }
160
161
  public static function include_asset($fn, $fn2 = null, $callback = null)
162
  {
163
    if (file_exists($fn)) {
164
      include $fn;
165
    } elseif ($fn2 && file_exists($fn2)) {
166
      include $fn2;
167
    } elseif (is_callable($callback)) {
168
      call_user_func($callback, $fn);
169
    }
170
  }
171
172
  public static function asset_find(array $fn = [])
173
  {
174
    $source = null;
175
    foreach ($fn as $src) {
176
      if ($src && !empty($src)) {
177
        if (file_exists($src) && is_file($src) && $src = realpath($src)) {
178
          $source = $src;
179
          break;
180
        }
181
      }
182
    }
183
184
    return $source;
185
  }
186
187
  /**
188
   * Sass Compiler.
189
   *
190
   * @requires shell_exec
191
   */
192
  public static function sass(string $path)
193
  {
194
    \Cookie\helper::one('sass' . self::$key, 'compiler', 1, function () use ($path) {
195
      if (is_file($path)) {
196
        if (self::is_windows()) {
197
          $path = self::fixSlash($path);
198
        }
199
        $exec = shell_exec('sass ' . $path);
200
        if (!empty($exec)) {
201
          //echo $exec;
202
          $save = preg_replace('/\.scss/s', '.css', $path);
203
          \Filemanager\file::file($save, $exec, true);
0 ignored issues
show
$exec of type null|string is incompatible with the type boolean expected by parameter $create of Filemanager\file::file(). ( Ignorable by Annotation )

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

203
          \Filemanager\file::file($save, /** @scrutinizer ignore-type */ $exec, true);
Loading history...
204
        }
205
      }
206
    });
207
  }
208
209
  /**
210
   * GET PHP ERROR LOG.
211
   *
212
   * @return string|null
213
   */
214
  public static function php_error_log(bool $onlypath = false)
215
  {
216
    $log = PHP_ERROR_FILE;
217
    if ($log = realpath($log)) {
218
      if ('DELETE' == $_SERVER['REQUEST_METHOD']) {
219
        if ('php' == self::is_header('Log')) {
220
          unlink($log);
221
        }
222
      }
223
      if (!$onlypath) {
224
        return read_file($log);
225
      } else {
226
        return $log;
227
      }
228
    }
229
  }
230
231
  /**
232
   * Check if header request has $any.
233
   *
234
   * @return string|null
235
   */
236
  public static function is_header(string $any)
237
  {
238
    $allHeaders = getallheaders();
239
240
    return array_key_exists($any, $allHeaders) ? $allHeaders[$any] : null;
0 ignored issues
show
It seems like $allHeaders can also be of type true; however, parameter $array of array_key_exists() does only seem to accept ArrayObject|array, maybe add an additional type check? ( Ignorable by Annotation )

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

240
    return array_key_exists($any, /** @scrutinizer ignore-type */ $allHeaders) ? $allHeaders[$any] : null;
Loading history...
241
  }
242
243
  public static function babel(string $path)
244
  {
245
    \Cookie\helper::one('babel' . self::$key, 'compiler', 1, function () use ($path) {
246
      if (is_file($path)) {
247
        if (self::is_windows()) {
248
          $path = self::fixSlash($path);
249
        }
250
        $exec = shell_exec('npx babel ' . $path);
251
        $save = \Filemanager\file::tmp() . '/js/babel/' . basename($path);
252
        if (!empty($exec)) {
253
          \Filemanager\file::file($save, $exec, true);
0 ignored issues
show
$exec of type null|string is incompatible with the type boolean expected by parameter $create of Filemanager\file::file(). ( Ignorable by Annotation )

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

253
          \Filemanager\file::file($save, /** @scrutinizer ignore-type */ $exec, true);
Loading history...
254
          $min = shell_exec('terser ' . self::fixSlash($save));
255
          /*if (!empty($min)) {
256
          echo $min;
257
          } else {
258
          echo $save;
259
          }*/
260
          if (!empty($min)) {
261
            $minjs = preg_replace('/\.babel\.js/s', '.min.js', $path);
262
            \Filemanager\file::file($minjs, $min, true);
263
          } else {
264
            $js = preg_replace('/\.babel\.js/s', '.js', $path);
265
            \Filemanager\file::file($js, $exec, true);
266
          }
267
        }
268
      }
269
    });
270
  }
271
272
  /**
273
   * Clean special characters from string.
274
   *
275
   * @param string $replace
276
   *
277
   * @return string
278
   */
279
  public static function clean_special_characters(string $string, $replace = '')
280
  {
281
    //$string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
282
    $string = self::clean_multiple_hypens($string);
283
284
    return preg_replace('/[^A-Za-z0-9\-]/', $replace, $string); // Removes special chars.
285
  }
286
287
  public static function clean_multiple_hypens($string)
288
  {
289
    $string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
290
    $string = preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
291
292
    return preg_replace('/-+/', '-', $string); // Replaces multiple hyphens with single one.
293
  }
294
295
  public static function clean_whitespace(string $str)
296
  {
297
    return preg_replace('/\s{1,99}/s', '', $str);
298
  }
299
300
  public static function webkit_asset(string $path, string $alternative = null)
301
  {
302
    $path = realpath($path);
303
    if (!$path && $alternative) {
304
      $path = realpath($alternative);
305
    }
306
    if ($path) {
307
      $root = realpath(ROOT);
308
      $pathNoRoot = helper::fixSlash(str_replace($root, '', $path));
309
310
      return self::base_url("/load-asset?src=$pathNoRoot");
311
    }
312
  }
313
314
  public static function load_asset($path)
315
  {
316
    $root = realpath(ROOT);
317
    if ($path = realpath($root . $path)) {
318
      $ext = pathinfo($path, PATHINFO_EXTENSION);
319
      //var_dump($path, $ext);
320
      if (self::headerExt($ext)) {
321
        http_response_code(200);
322
        include $path;
323
      }
324
    }
325
  }
326
327
  public static function headerExt($ext)
328
  {
329
    $mimes = include __DIR__ . '/mimes.php';
330
    if (isset($mimes[$ext][0])) {
331
      if (!headers_sent()) {
332
        header("Content-Type: {$mimes[$ext][0]}");
333
334
        return true;
335
      }
336
    }
337
338
    return false;
339
  }
340
341
  /**
342
   * Parse URL deeper.
343
   *
344
   * @param string $url
345
   * @param bool   $encoded
346
   *
347
   * @return parse_url
0 ignored issues
show
The type MVC\parse_url was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
348
   */
349
  public static function parse_url2($url, $encoded = false)
350
  {
351
    if ($encoded) {
352
      $url = urldecode($url);
353
    }
354
    $url = html_entity_decode($url);
355
    $parts = parse_url($url);
356
    if (!isset($parts['path'])) {
357
      $parts['path'] = '';
358
    }
359
    if (isset($parts['query'])) {
360
      parse_str($parts['query'], $query);
361
      $parts['original_query'] = $parts['query'];
362
      $parts['query'] = $query;
363
    }
364
365
    return array_merge($parts);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_merge($parts) returns the type array which is incompatible with the documented return type MVC\parse_url.
Loading history...
366
  }
367
368
  /**
369
   * Fix path string `default OS` separate slash and replaced by `/`
370
   * * WIN (\\)
371
   * * LINUX (/).
372
   *
373
   * @return string
374
   */
375
  public static function fixSlash(string $path, int $maxlength = 10)
376
  {
377
    $re = '/\\' . DIRECTORY_SEPARATOR . '{1,' . $maxlength . '}/s';
378
    //var_dump($re);
379
    return preg_replace($re, '/', $path);
380
  }
381
382
  /**
383
   * Get path base URL
384
   * * example (/cookie/file.html) -> (https://httpbin.org/cookie/file.html).
385
   *
386
   * @param string $path     pathname from base url
387
   * @param bool   $forceSSL force https protocol returned
388
   *                         * true or false or null
389
   *
390
   * @return string protocol://origin/pathname
391
   */
392
  public static function base_url(string $path, bool $forceSSL = false)
393
  {
394
    $protocol = isset($_SERVER['HTTPS']) && 'on' === $_SERVER['HTTPS'] ? 'https' : 'http';
395
    if ($forceSSL) {
396
      $protocol = 'https';
397
    }
398
399
    return $protocol . "://{$_SERVER['HTTP_HOST']}{$path}";
400
  }
401
402
  /**
403
   * Get current URL.
404
   *
405
   * @param bool $forceSSL force https protocol returned
406
   *                       * true or false or null
407
   *
408
   * @return string protocol://origin/pathname
409
   */
410
  public static function geturl(bool $forceSSL = false)
411
  {
412
    $protocol = isset($_SERVER['HTTPS']) && 'on' === $_SERVER['HTTPS'] ? 'https' : 'http';
413
    if ($forceSSL) {
414
      $protocol = 'https';
415
    }
416
417
    return $protocol . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
418
  }
419
420
  private static $origin = null;
421
422
  public static function getOrigin()
423
  {
424
    if (!self::$origin) {
425
      $protocol = isset($_SERVER['HTTPS']) && 'on' === $_SERVER['HTTPS'] ? 'https' : 'http';
426
      self::$origin = $protocol . "://$_SERVER[HTTP_HOST]";
427
    }
428
429
    return self::$origin;
430
  }
431
432
  private static $canonical = [];
433
  /**
434
   * get canonical url
435
   *
436
   * @param string $url null for current page
437
   * @param boolean $whos include host or not (http://domain)
438
   * @return void
439
   */
440
  public static function get_canonical(string $url = null, bool $whos = true)
441
  {
442
    if (null === $url) {
443
      $url = self::geturl();
444
    }
445
    if (isset(self::$canonical[$url])) {
446
      return self::$canonical[$url];
447
    } else {
448
      $url_parts = parse_url($url);
449
      if ($whos) {
450
        self::$canonical[$url] = $url_parts['scheme'] . '://' . $url_parts['host'] . (isset($url_parts['path']) ? $url_parts['path'] : '');
451
      } else {
452
        self::$canonical[$url] = (isset($url_parts['path']) ? $url_parts['path'] : '');
453
      }
454
    }
455
456
    return self::$canonical[$url];
457
  }
458
459
  /**
460
   * Get `request uri` without parameter.
461
   *
462
   * @param string $url
463
   *
464
   * @return string
465
   */
466
  public static function get_clean_uri(string $url = null)
467
  {
468
    if (null === $url) {
469
      $url = self::geturl();
470
    }
471
472
    return self::parse_url2($url)['path'];
473
  }
474
475
  /**
476
   * Check if current is localhost.
477
   *
478
   * @param string $regex new regex
479
   *
480
   * @return bool
481
   */
482
  public static function isLocal(string $regex = null)
483
  {
484
    $match = preg_match('/127\.0\.0\.0\.1|localhost|^192\.168/s', $_SERVER['HTTP_HOST']) ? true : false;
485
486
    $whitelist = array(
487
      '127.0.0.1',
488
      '::1'
489
    );
490
491
    if (!in_array($_SERVER['REMOTE_ADDR'], $whitelist)) {
492
      $match = false;
493
    } else {
494
      if ($regex) {
495
        $match = $match || preg_match($regex, $_SERVER['HTTP_HOST']) ? true : false;
496
      } else {
497
        $match = true;
498
      }
499
    }
500
501
    return $match;
502
  }
503
504
  /**
505
   * Set cookie helper.
506
   *
507
   * @param mixed     $value
508
   * @param int|float $day
509
   * @param string    $path
510
   * @param string    $domain
511
   * @param bool      $secure
512
   * @param bool      $httponly
513
   */
514
  public static function setcookie(string $name, $value = true, $day, $path = '/', $domain = '', $secure = false, $httponly = false)
515
  {
516
    settype($day, 'integer');
517
    if (empty($domain)) {
518
      $domain = $_SERVER['HTTP_HOST'];
519
    }
520
    if (empty($path)) {
521
      $path = '/';
522
    }
523
524
    return setcookie($name, $value, time() + 60 * 60 * 24 * $day, $path, $domain, $secure, $httponly);
0 ignored issues
show
It seems like $value can also be of type true; however, parameter $value of setcookie() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

524
    return setcookie($name, /** @scrutinizer ignore-type */ $value, time() + 60 * 60 * 24 * $day, $path, $domain, $secure, $httponly);
Loading history...
525
  }
526
527
  /**
528
   * Get Cookie By Name.
529
   */
530
  public static function getcookie(string $name)
531
  {
532
    if (isset($_COOKIE[$name])) {
533
      return $_COOKIE[$name];
534
    }
535
536
    return null;
537
  }
538
539
  public static function delcookie(string $name)
540
  {
541
    if (isset($_COOKIE[$name])) {
542
      unset($_COOKIE[$name]);
543
      setcookie($name, null, -1, '/');
544
545
      return true;
546
    } else {
547
      return false;
548
    }
549
  }
550
551
  /**
552
   * Get request data
553
   * * $_GET[$name]
554
   * * $_REQUEST[$name]
555
   * * $_POST[$name].
556
   *
557
   * @param string $type request method
558
   *                     * get = only accept get
559
   *                     * post = only accept post
560
   *                     * any = accept all request
561
   * @param mixed  $name What data requests will you take?
562
   *
563
   * @return string|null
564
   */
565
  public static function request_data(string $type = 'get', $name)
566
  {
567
    $method = $_SERVER['REQUEST_METHOD'];
568
    $allowed = $method == strtoupper($type) || 'any' == $type;
569
    //var_dump($allowed);
570
    if ($allowed) {
571
      if (isset($_REQUEST[$name])) {
572
        return $_REQUEST[$name];
573
      }
574
    }
575
  }
576
577
  /**
578
   * Detect current OS is Windows.
579
   *
580
   * @return bool
581
   */
582
  public static function is_windows()
583
  {
584
    return 'WIN' === strtoupper(substr(PHP_OS, 0, 3));
585
  }
586
587
  public static function platformSlashes($path)
588
  {
589
    $path = str_replace('//', '/', $path);
590
591
    return str_replace('/', DIRECTORY_SEPARATOR, $path);
592
  }
593
594
  /**
595
   * Cors domain verify, detect AJAX, and validate AJAX CORS.
596
   *
597
   * @param bool $print_server Debug mode
598
   *
599
   * @todo only allow CORS request
600
   */
601
  public static function cors($print_server = false)
602
  {
603
    $final = true;
604
    $xrequested = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? $_SERVER['HTTP_X_REQUESTED_WITH'] : false;
605
606
    $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : false;
607
608
    if (isset($_SERVER['HTTP_ACCEPT']) && preg_match('/^application\/json/s', $_SERVER['HTTP_ACCEPT'])) {
609
      header('Content-type: application/json; charset=utf-8');
610
    }
611
    header('Access-Control-Allow-Origin: *'); //allow all AJAX REQUEST
612
613
    if (false !== $xrequested) {
614
      if ('xmlhttprequest' != strtolower($xrequested)) {
615
        $_SERVER['PHP_LINE'] = __LINE__;
616
617
        if ($print_server) {
618
          return $_SERVER;
619
        } else {
620
          return false;
621
        }
622
      } else {
623
        if (isset($_SERVER['HTTP_SEC_FETCH_SITE'], $_SERVER['HTTP_SEC_FETCH_MODE'], $_SERVER['HTTP_REFERER'], $_SERVER['HTTP_ORIGIN'], $_SERVER['HTTP_USER_AGENT'])) {
624
          $parseRef = parse_url($_SERVER['HTTP_REFERER']);
625
          $parseOri = parse_url($_SERVER['HTTP_ORIGIN']);
626
          if (!isset($parseOri['host']) || !isset($parseRef['host'])) {
627
            $_SERVER['PHP_LINE'] = __LINE__;
628
629
            if ($print_server) {
630
              return $_SERVER;
631
            } else {
632
              return false;
633
            }
634
          }
635
          if ($parseOri['host'] != $parseRef['host']) {
636
            $_SERVER['PHP_LINE'] = __LINE__;
637
638
            if ($print_server) {
639
              return $_SERVER;
640
            } else {
641
              return false;
642
            }
643
          }
644
          if ('same-origin' == $_SERVER['HTTP_SEC_FETCH_SITE'] && 'cors' == $_SERVER['HTTP_SEC_FETCH_MODE']) {
645
            return $parseOri['host'] == $parseRef['host'];
646
          } else {
647
            $_SERVER['PHP_LINE'] = __LINE__;
648
            if ($print_server) {
649
              return $_SERVER;
650
            } else {
651
              return false;
652
            }
653
          }
654
        }
655
      }
656
    } else {
657
      $final = false;
658
      $_SERVER['PHP_LINE'] = __LINE__;
659
    }
660
661
    if ($origin) {
662
      header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
663
      header('Access-Control-Expose-Headers: date,content-type,transfer-encoding,connection,access-control-allow-origin,server,x-xss-protection,x-content-type-options,x-request-id,content-encoding,x-final-url');
664
      header('Access-Control-Allow-Credentials: true');
665
      header('Access-Control-Max-Age: 86400');    // cache for 1 day
666
      if (isset($_SERVER['HTTP_REFERER'])) {
667
        $parseRef = parse_url($_SERVER['HTTP_REFERER']);
668
        $parseOri = parse_url($_SERVER['HTTP_ORIGIN']);
669
        if (!isset($parseOri['host']) || !isset($parseRef['host'])) {
670
          $_SERVER['PHP_LINE'] = __LINE__;
671
          if ($print_server) {
672
            return $_SERVER;
673
          } else {
674
            return false;
675
          }
676
        }
677
        if ($parseOri['host'] != $parseRef['host']) {
678
          $_SERVER['PHP_LINE'] = __LINE__;
679
          if ($print_server) {
680
            return $_SERVER;
681
          } else {
682
            return false;
683
          }
684
        }
685
      } else {
686
        $_SERVER['PHP_LINE'] = __LINE__;
687
        if ($print_server) {
688
          return $_SERVER;
689
        } else {
690
          return false;
691
        }
692
      }
693
    }
694
695
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
696
      // may also be using PUT, PATCH, HEAD etc
697
      header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
698
    }
699
700
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
701
      header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
702
    } else {
703
      header('Access-Control-Allow-Headers: X-Requested-With');
704
    }
705
706
    if (!isset($_SERVER['HTTP_ACCEPT'])) {
707
      $final = false;
708
      $_SERVER['PHP_LINE'] = __LINE__;
709
    }
710
    /*
711
     * AJAX request absolutely send http-origin and x-requested-with
712
     */
713
    if (!isset($_SERVER['HTTP_ORIGIN']) && !$xrequested) {
714
      $_SERVER['PHP_LINE'] = __LINE__;
715
      $final = false;
716
    }
717
    if (!isset($_SERVER['HTTP_REFERER'])) {
718
      $_SERVER['PHP_LINE'] = __LINE__;
719
      $final = false;
720
    }
721
    if (!isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
722
      $_SERVER['PHP_LINE'] = __LINE__;
723
      $final = false;
724
    }
725
726
    /*
727
     * disallow if request content-type is HTML
728
     */
729
    if (isset($_SERVER['HTTP_CONTENT_TYPE']) && !preg_match('/^text\/html/s', $_SERVER['HTTP_CONTENT_TYPE'])) {
730
      $_SERVER['PHP_LINE'] = __LINE__;
731
      $final = false;
732
    }
733
    if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
734
      $_SERVER['PHP_LINE'] = __LINE__;
735
      $final = false;
736
    }
737
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
738
      $_SERVER['PHP_LINE'] = __LINE__;
739
      $final = false;
740
    }
741
    if (!self::isLocal()) {
742
      $_SERVER['PHP_LINE'] = __LINE__;
743
      $final = $final && isset($_SERVER['UNIQUE_ID']);
744
    }
745
746
    //var_dump($final);
747
    //var_dump(isset($_SERVER['UNIQUE_ID']));
748
    if (!$final && $print_server) {
749
      //$_SERVER['PHP_LINE'] = __LINE__;
750
      //var_dump($_SERVER['PHP_LINE'], $final);
751
      ksort($_SERVER);
752
753
      return $_SERVER;
754
    }
755
    //var_dump($_SERVER['PHP_LINE']);
756
    if ($final) {
757
      return true;
758
    }
759
760
    return false;
761
  }
762
763
  /**
764
   * Check if a given ip is in a network.
765
   *
766
   * @see https://gist.github.com/ryanwinchester/578c5b50647df3541794
767
   *
768
   * @param string $ip    IP to check in IPV4 format eg. 127.0.0.1
769
   * @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
770
   *
771
   * @return bool true if the ip is in this range / false if not
772
   */
773
  public static function ip_in_range(string $ip, $range)
774
  {
775
    if (false == strpos($range, '/')) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($range, '/') of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
776
      $range .= '/32';
777
    }
778
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
779
      return false;
780
    }
781
782
    // $range is in IP/CIDR format eg 127.0.0.1/24
783
    list($range, $netmask) = explode('/', trim($range), 2);
784
    //var_dump($netmask);
785
786
    $ip_decimal = ip2long($ip);
787
    $range_decimal = ip2long($range);
788
    $wildcard_decimal = pow(2, (32 - $netmask)) - 1;
789
    $netmask_decimal = ~$wildcard_decimal;
790
791
    return ($ip_decimal & $netmask_decimal) == ($range_decimal & $netmask_decimal);
792
  }
793
794
  public static function ip_in_multirange($ip, array $ranges)
795
  {
796
    $in_range = false;
797
    foreach ($ranges as $range) {
798
      if (self::ip_in_range($ip, $range)) {
799
        $in_range = true;
800
        break;
801
      }
802
    }
803
804
    return $in_range;
805
  }
806
807
  /**
808
   * Check if request is google.
809
   *
810
   * @return bool
811
   */
812
  public static function is_google()
813
  {
814
    $file = file(__DIR__ . '/conf/google_ips.txt', FILE_SKIP_EMPTY_LINES);
815
    $ip = self::getRequestIP();
816
    $result = false;
817
    foreach ($file as $range) {
818
      if (self::ip_in_range($ip, $range)) {
819
        $result = true;
820
        break;
821
      }
822
    }
823
824
    return $result;
825
  }
826
827
  public static function get_client_ip()
828
  {
829
    $ipaddress = null;
830
    if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
831
      $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
832
    }
833
    if (isset($_SERVER['HTTP_CLIENT_IP'])) {
834
      $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
835
    } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
836
      $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
837
    } elseif (isset($_SERVER['HTTP_X_FORWARDED'])) {
838
      $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
839
    } elseif (isset($_SERVER['HTTP_FORWARDED_FOR'])) {
840
      $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
841
    } elseif (isset($_SERVER['HTTP_FORWARDED'])) {
842
      $ipaddress = $_SERVER['HTTP_FORWARDED'];
843
    } elseif (isset($_SERVER['REMOTE_ADDR'])) {
844
      $ipaddress = $_SERVER['REMOTE_ADDR'];
845
    }
846
847
    return $ipaddress;
848
  }
849
850
  public static function _cloudflare_CheckIP($ip)
851
  {
852
    $cf_ips = [
853
      '199.27.128.0/21',
854
      '173.245.48.0/20',
855
      '103.21.244.0/22',
856
      '103.22.200.0/22',
857
      '103.31.4.0/22',
858
      '141.101.64.0/18',
859
      '108.162.192.0/18',
860
      '190.93.240.0/20',
861
      '188.114.96.0/20',
862
      '197.234.240.0/22',
863
      '198.41.128.0/17',
864
      '162.158.0.0/15',
865
      '104.16.0.0/12',
866
    ];
867
    $is_cf_ip = false;
868
    foreach ($cf_ips as $cf_ip) {
869
      if (self::ip_in_range($ip, $cf_ip)) {
870
        $is_cf_ip = true;
871
        break;
872
      }
873
    }
874
875
    return $is_cf_ip;
876
  }
877
878
  public static function _cloudflare_Requests_Check()
879
  {
880
    $flag = true;
881
882
    if (!isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
883
      $flag = false;
884
    }
885
    if (!isset($_SERVER['HTTP_CF_IPCOUNTRY'])) {
886
      $flag = false;
887
    }
888
    if (!isset($_SERVER['HTTP_CF_RAY'])) {
889
      $flag = false;
890
    }
891
    if (!isset($_SERVER['HTTP_CF_VISITOR'])) {
892
      $flag = false;
893
    }
894
895
    return $flag;
896
  }
897
898
  public static function isCloudflare()
899
  {
900
    $ipCheck = self::_cloudflare_CheckIP($_SERVER['REMOTE_ADDR']);
901
    $requestCheck = self::_cloudflare_Requests_Check();
902
903
    return $ipCheck && $requestCheck;
904
  }
905
906
  // Use when handling ip's
907
  public static function getRequestIP()
908
  {
909
    $check = self::isCloudflare();
910
911
    if ($check) {
912
      return $_SERVER['HTTP_CF_CONNECTING_IP'];
913
    } else {
914
      return self::get_client_ip();
915
    }
916
  }
917
918
  /**
919
   * Get Useragent.
920
   *
921
   * @return string
922
   */
923
  public static function useragent()
924
  {
925
    return $_SERVER['HTTP_USER_AGENT'];
926
  }
927
928
  public static function print_server()
929
  {
930
    return join(PHP_EOL, $_SERVER);
931
  }
932
933
  /**
934
   * Get URL from local file
935
   *
936
   * @param string|array $path destinations
937
   * * `array` will be looped, which found first, return them
938
   * @param boolean $cache
939
   * @return string if empty == not found
940
   */
941
  public static function get_url_path($path, bool $cache = null)
942
  {
943
    $load = function (string $path) use ($cache) {
944
      if ($realpath = realpath($path)) {
945
        $f = str_replace(realpath($_SERVER['DOCUMENT_ROOT']), '', $realpath);
946
947
        $ret = self::fixSlash($f);
948
        if (true === $cache) {
949
          $ret .= '?cache=' . CONFIG['cache']['key'];
950
        }
951
952
        return $ret;
953
      }
954
    };
955
    if (is_string($path)) {
956
      if ($load($path)) {
957
        return $load($path);
958
      }
959
    } else if (is_array($path)) {
0 ignored issues
show
The condition is_array($path) is always true.
Loading history...
960
      foreach ($path as $dest) {
961
        if ($load($dest)) {
962
          return $load($dest);
963
          break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
964
        }
965
      }
966
    }
967
968
    return '';
969
  }
970
971
  public static function ddos_key()
972
  {
973
    $secure_cookie_label = 'DDOS';
974
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
975
      exit(\JSON\json::json(['error' => true, 'message' => 'BOT Detected']));
0 ignored issues
show
Are you sure the usage of JSON\json::json(array('e...ge' => 'BOT Detected')) targeting JSON\json::json() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Using exit here is not recommended.

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

Loading history...
976
    }
977
    //$secure_cookie_label .= date('Ymd');
978
    $secure_cookie_label .= $_SERVER['HTTP_USER_AGENT'];
979
    $secure_cookie_label = md5($secure_cookie_label);
980
981
    return $secure_cookie_label;
982
  }
983
984
  /**
985
   * Minify HTML.
986
   *
987
   * @param string $buffer
988
   */
989
  public static function sanitize_output($buffer)
990
  {
991
    if (!is_string($buffer)) {
0 ignored issues
show
The condition is_string($buffer) is always true.
Loading history...
992
      return $buffer;
993
    }
994
    $search = [
995
      '/\>[^\S ]+/s',     // strip whitespaces after tags, except space
996
      '/[^\S ]+\</s',     // strip whitespaces before tags, except space
997
      '/(\s)+/s',         // shorten multiple whitespace sequences
998
      '/<!--(.|\s)*?-->/', // Remove HTML comments
999
    ];
1000
1001
    $replace = [
1002
      '>',
1003
      '<',
1004
      '\\1',
1005
      '',
1006
    ];
1007
1008
    $buffer = preg_replace($search, $replace, $buffer);
1009
1010
    return $buffer;
1011
  }
1012
1013
  public static function trycatch($try)
1014
  {
1015
    try {
1016
      if (is_callable($try)) {
1017
        call_user_func($try);
1018
      }
1019
    } catch (\Throwable $th) {
1020
      if (ob_get_level()) {
1021
        ob_end_clean();
1022
        ob_start();
1023
      }
1024
      $title = 'ERROR';
1025
      $desc = $th->getMessage();
1026
      if (isset($_REQUEST['dmp']) || 'development' == \MVC\router::get_env()) {
1027
        $desc .= '<pre style="word-wrap: break-word;">' . nl2br(json_encode($th->getTrace(), JSON_UNESCAPED_UNICODE || JSON_PRETTY_PRINT || JSON_UNESCAPED_SLASHES)) . '</pre>';
0 ignored issues
show
MVC\JSON_UNESCAPED_UNICO...\JSON_UNESCAPED_SLASHES of type boolean is incompatible with the type integer expected by parameter $flags of json_encode(). ( Ignorable by Annotation )

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

1027
        $desc .= '<pre style="word-wrap: break-word;">' . nl2br(json_encode($th->getTrace(), /** @scrutinizer ignore-type */ JSON_UNESCAPED_UNICODE || JSON_PRETTY_PRINT || JSON_UNESCAPED_SLASHES)) . '</pre>';
Loading history...
1028
      }
1029
      include __DIR__ . '/themes/alert/content.php';
1030
      exit;
0 ignored issues
show
Using exit here is not recommended.

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

Loading history...
1031
    } finally {
1032
    }
1033
  }
1034
}
1035