Passed
Push — 2.x ( daf3a4...83ed90 )
by Terry
02:01
created

load_css()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * php version 7.1.0
11
 *
12
 * @category  Web-security
13
 * @package   Shieldon
14
 * @author    Terry Lin <[email protected]>
15
 * @copyright 2019 terrylinooo
16
 * @license   https://github.com/terrylinooo/shieldon/blob/2.x/LICENSE MIT
17
 * @link      https://github.com/terrylinooo/shieldon
18
 * @see       https://shieldon.io
19
 */
20
21
declare(strict_types=1);
22
23
namespace Shieldon\Firewall;
24
25
use Psr\Http\Message\ServerRequestInterface;
26
use Psr\Http\Message\ResponseInterface;
27
use Shieldon\Firewall\HttpFactory;
28
use Shieldon\Firewall\Utils\Collection;
29
use Shieldon\Firewall\Utils\Container;
30
31
use function explode;
32
use function file_exists;
33
use function func_get_arg;
34
use function func_num_args;
35
use function implode;
36
use function is_array;
37
use function is_null;
38
use function preg_split;
39
use function round;
40
use function shell_exec;
41
use function str_repeat;
42
use function str_replace;
43
use function stripos;
44
use function strtoupper;
45
use function substr;
46
use function sys_getloadavg;
47
use function trim;
48
use const PHP_OS;
49
50
/**
51
 * This value will be only displayed on Firewall Panel.
52
 */
53
define('SHIELDON_FIREWALL_VERSION', '2.0');
54
55
/**
56
 * Just use PSR-4 autoloader to load those helper functions.
57
 */
58
class Helpers
59
{
60
61
}
62
63
/**
64
 * Get user lang.
65
 * 
66
 * This method is a part of  __()
67
 *
68
 * @return string
69
 */
70
function get_user_lang(): string
71
{
72
    static $lang;
73
74
    if (!$lang) {
75
        $lang = 'en';
76
77
        // Fetch session variables.
78
        $session = get_session();
79
        $panelLang = $session->get('shieldon_panel_lang');
80
        $uiLang = $session->get('shieldon_ui_lang');
81
    
82
        if (!empty($panelLang)) {
83
            $lang = $panelLang;
84
        } elseif (!empty($uiLang)) {
85
            $lang = $uiLang;
86
        }
87
    }
88
89
    return $lang;
90
}
91
92
/**
93
 * Include i18n file.
94
 * 
95
 * This method is a part of  __()
96
 *
97
 * @param string $lang     The language code.
98
 * @param string $filename The i18n language pack file.
99
 *
100
 * @return void
101
 */
102
function include_i18n_file(string $lang, string $filename): array
103
{
104
    $content = [];
105
    $lang = str_replace('-', '_', $lang);
106
107
    if (stripos($lang, 'zh_') !== false) {
108
        if (stripos($lang, 'zh_CN') !== false) {
109
            $lang = 'zh_CN';
110
        } else {
111
            $lang = 'zh';
112
        }
113
    }
114
115
    $file = __DIR__ . '/../../localization/' . $lang . '/' . $filename . '.php';
116
    
117
    if (file_exists($file)) {
118
        $content = include $file;
119
    }
120
121
    return $content;
122
}
123
124
/**
125
 * Get locale message.
126
 *
127
 * @return string
128
 */
129
function __(): string
130
{
131
    /**
132
     * Load locale string from i18n files and store them into this array 
133
     * for further use.
134
     * 
135
     * @var array 
136
     */
137
    static $i18n;
138
139
    /**
140
     * Check the file exists for not.
141
     *
142
     * @var array 
143
     */
144
    static $fileChecked;
145
146
    $num = func_num_args();
147
148
    $filename    = func_get_arg(0); // required.
149
    $langcode    = func_get_arg(1); // required.
150
    $placeholder = ($num > 2) ? func_get_arg(2) : '';
151
    $replacement = ($num > 3) ? func_get_arg(3) : [];
152
    $lang        = get_user_lang();
153
154
    if (empty($i18n[$filename]) && empty($fileChecked[$filename])) {
155
        $fileChecked[$filename] = true;
156
        $i18n[$filename] = include_i18n_file($lang, $filename);
157
    }
158
159
    // If we don't get the string from the localization file, use placeholder 
160
    // instead.
161
    $resultString = $placeholder;
162
163
    if (!empty($i18n[$filename][$langcode])) {
164
        $resultString = $i18n[$filename][$langcode];
165
    }
166
167
    if (is_array($replacement)) { 
168
        /**
169
         * Example:
170
         *     __('test', 'example_string', 'Search results: {0} items. Total items: {1}.', [5, 150]);
171
         * 
172
         * Result:
173
         *     Search results: 5 items. Total items: 150.
174
         */
175
        foreach ($replacement as $i => $r) {
176
            $resultString = str_replace('{' . $i . '}', $replacement[$i], $resultString);
177
        }
178
    }
179
    
180
    return str_replace("'", '’', $resultString);
181
}
182
183
/**
184
 * Echo string from __()
185
 *
186
 * @return void
187
 */
188
function _e(): void
189
{
190
    $num = func_num_args();
191
192
    $filename    = func_get_arg(0); // required.
193
    $langcode    = func_get_arg(1); // required.
194
    $placeholder = ($num > 2) ? func_get_arg(2) : '';
195
    $replacement = ($num > 3) ? func_get_arg(3) : [];
196
197
    echo __($filename, $langcode, $placeholder, $replacement);
198
}
199
200
/**
201
 * Mask strings with asterisks.
202
 *
203
 * @param string $str The text.
204
 *
205
 * @return string
206
 */
207
function mask_string($str): string
208
{
209
    if (filter_var($str, FILTER_VALIDATE_IP) !== false) {
210
        $tmp = explode('.', $str);
211
        $tmp[0] = '*';
212
        $tmp[1] = '*';
213
        $masked = implode('.', $tmp);
214
215
    } else {
216
        $masked =  str_repeat('*', strlen($str) - 6) . substr($str, -6);
217
    }
218
219
    return $masked;
220
}
221
222
/**
223
 * Get current CPU usage information.
224
 *
225
 * This function is only used in sending notifications and it is unavailable 
226
 * on Win system. If you are using shared hosting and your hosting provider 
227
 * has disabled `sys_getloadavg` and `shell_exec`, it won't work either.
228
 *
229
 * @return string
230
 */
231
function get_cpu_usage(): string
232
{
233
    $return = '';
234
235
    // This feature is not available on Windows platform.
236
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
237
        return $return;
238
    }
239
240
    $cpuLoads = @sys_getloadavg();
241
    $cpuCores = trim(@shell_exec("grep -P '^processor' /proc/cpuinfo|wc -l"));
242
243
    if (!empty($cpuCores) && !empty($cpuLoads)) {
244
        $return = round($cpuLoads[1] / ($cpuCores + 1) * 100, 0) . '%';
245
    }
246
    return $return;
247
}
248
249
/**
250
 * Get current RAM usage information. 
251
 *
252
 * If you are using shared hosting and your hosting provider has disabled 
253
 * `shell_exec`, this function may not work as expected.
254
 *
255
 * @return string
256
 */
257
function get_memory_usage(): string
258
{
259
    $return = '';
260
261
    // This feature is not available on Windows platform.
262
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
263
        return $return;
264
    }
265
266
    $freeResult = explode("\n", trim(@shell_exec('free')));
267
268
    if (!empty($freeResult)) {
269
        $parsed = preg_split("/[\s]+/", $freeResult[1]);
270
        $return = round($parsed[2] / $parsed[1] * 100, 0) . '%';
271
    }
272
    return $return;
273
}
274
275
/**
276
 * The default settings of Shieldon core.
277
 *
278
 * @return array
279
 */
280
function get_default_properties(): array
281
{
282
    return [
283
284
        'time_unit_quota' => [
285
            's' => 2,
286
            'm' => 10,
287
            'h' => 30,
288
            'd' => 60
289
        ],
290
291
        'time_reset_limit'       => 3600,
292
        'interval_check_referer' => 5,
293
        'interval_check_session' => 30,
294
        'limit_unusual_behavior' => [
295
            'cookie'  => 5,
296
            'session' => 5,
297
            'referer' => 10
298
        ],
299
300
        'cookie_name'         => 'ssjd',
301
        'cookie_domain'       => '',
302
        'cookie_value'        => '1',
303
        'display_online_info' => true,
304
        'display_user_info'   => false,
305
306
        /**
307
         * If you set this option enabled, Shieldon will record every CAPTCHA fails 
308
         * in a row, once that user have reached the limitation number, Shieldon will
309
         * put it as a blocked IP in rule table, until the new data cycle begins.
310
         * 
311
         * Once that user have been blocked, they are still access the warning page, 
312
         * it means that they are not humain for sure, so let's throw them into the 
313
         * system firewall and say goodbye to them forever.
314
         */
315
        'deny_attempt_enable' => [
316
            'data_circle'     => false,
317
            'system_firewall' => false,
318
        ],
319
        'deny_attempt_notify' => [
320
            'data_circle'     => false,
321
            'system_firewall' => false,
322
        ],
323
        'deny_attempt_buffer' => [
324
            'data_circle'     => 10,
325
            'system_firewall' => 10,
326
        ],
327
328
        /**
329
         * To prevent dropping social platform robots into iptables firewall, such 
330
         * as Facebook, Line and others who scrape snapshots from your web pages, 
331
         * you should adjust the values below to fit your needs. (unit: second)
332
         */
333
        'record_attempt_detection_period' => 5, // 5 seconds.
334
335
        // Reset the counter after n second.
336
        'reset_attempt_counter' => 1800, // 30 minutes.
337
338
        // System-layer firewall, ip6table service watches this folder to 
339
        // receive command created by Shieldon Firewall.
340
        'iptables_watching_folder' => '/tmp/',
341
    ];
342
}
343
344
/**
345
 * PSR-7 HTTP server request
346
 *
347
 * @return ServerRequestInterface
348
 */
349
function get_request(): ServerRequestInterface
350
{
351
    $request = Container::get('request');
352
353
    if (is_null($request)) {
354
        $request = HttpFactory::createRequest();
355
        Container::set('request', $request);
356
    }
357
358
    return $request;
359
}
360
361
/**
362
 * PSR-7 HTTP response.
363
 *
364
 * @return ResponseInterface
365
 */
366
function get_response(): ResponseInterface
367
{
368
    $response = Container::get('response');
369
370
    if (is_null($response)) {
371
        $response = HttpFactory::createResponse();
372
        Container::set('response', $response);
373
    }
374
375
    return $response;
376
}
377
378
/**
379
 * Session
380
 *
381
 * @return Collection
382
 */
383
function get_session(): Collection
384
{
385
    $session = Container::get('session');
386
387
    if (is_null($session)) {
388
        $session = HttpFactory::createSession();
389
        Container::set('session', $session);
390
    }
391
392
    return $session;
393
}
394
395
/**
396
 * Set a PSR-7 HTTP server request into container.
397
 *
398
 * @param ServerRequestInterface $request The PSR-7 server request.
399
 *
400
 * @return void
401
 */
402
function set_request(ServerRequestInterface $request): void
403
{
404
    Container::set('request', $request, true);
405
}
406
407
/**
408
 * Set a PSR-7 HTTP response into container.
409
 *
410
 * @param ResponseInterface $response The PSR-7 server response.
411
 *
412
 * @return void
413
 */
414
function set_response(ResponseInterface $response): void
415
{
416
    Container::set('response', $response, true);
417
}
418
419
/**
420
 * Unset cookie.
421
 *
422
 * @param string|null $name The name (key) in the array of the superglobal.
423
 *
424
 * @return void
425
 */
426
function unset_global_cookie($name = null): void
427
{
428
    if (empty($name)) {
429
        $cookieParams = get_request()->getCookieParams();
430
        set_request(get_request()->withCookieParams([]));
431
        foreach (array_keys($cookieParams) as $name) {
432
            set_response(
433
                get_response()->withHeader(
434
                    'Set-Cookie',
435
                    "$name=; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0"
436
                )
437
            );
438
        }
439
        $_COOKIE = [];
440
441
        return;
442
    }
443
444
    $cookieParams = get_request()->getCookieParams();
445
    unset($cookieParams[$name]);
446
447
    set_request(
448
        get_request()->withCookieParams(
449
            $cookieParams
450
        )
451
    );
452
453
    set_response(
454
        get_response()->withHeader(
455
            'Set-Cookie',
456
            "$name=; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0"
457
        )
458
    );
459
    // Prevent direct access to superglobal.
460
    unset($_COOKIE[$name]);
461
}
462
463
/**
464
 * Unset post.
465
 *
466
 * @param string|null $name The name (key) in the array of the superglobal.
467
 *
468
 * @return void
469
 */
470
function unset_global_post($name = null): void
471
{
472
    if (empty($name)) {
473
        set_request(get_request()->withParsedBody([]));
474
        $_POST = [];
475
476
        return;
477
    }
478
479
    $postParams = get_request()->getParsedBody();
480
    unset($postParams[$name]);
481
    set_request(get_request()->withParsedBody($postParams));
482
    unset($_POST[$name]);
483
}
484
485
/**
486
 * Unset get.
487
 *
488
 * @param string|null $name The name (key) in the array of the superglobal.
489
 *
490
 * @return void
491
 */
492
function unset_global_get($name = null): void
493
{
494
    if (empty($name)) {
495
        set_request(get_request()->withQueryParams([]));
496
        $_GET = [];
497
498
        return;
499
    }
500
501
    $getParams = get_request()->getQueryParams();
502
    unset($getParams[$name]);
503
    set_request(get_request()->withQueryParams($getParams));
504
    unset($_GET[$name]);
505
}
506
507
/**
508
 * Unset session.
509
 *
510
 * @param string|null $name The name (key) in the array of the superglobal.
511
 *
512
 * @return void
513
 */
514
function unset_global_session($name = null): void
515
{
516
    if (empty($name)) {
517
        get_session()->clear();
518
        $_SESSION = [];
519
520
        return;
521
    }
522
523
    get_session()->remove($name);
524
    unset($_SESSION[$name]);
525
}
526
527
/**
528
 * Unset a variable of superglobal.
529
 *
530
 * @param string|null $name The name (key) in the array of the superglobal.
531
 *                          If $name is null that means clear all.
532
 * @param string      $type The type of the superglobal.
533
 *
534
 * @return void
535
 */
536
function unset_superglobal($name, string $type): void
537
{
538
    $types = [
539
        'get',
540
        'post',
541
        'cookie',
542
        'session',
543
    ];
544
545
    if (!in_array($type, $types)) {
546
        return;
547
    }
548
549
    $method = '\Shieldon\Firewall\unset_global_' . $type;
550
    $method($name, $type);
551
}
552