Passed
Push — 2.x ( b39b75...fea0f7 )
by Terry
01:57
created

BaseController::respond()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 8
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
11
declare(strict_types=1);
12
13
namespace Shieldon\Firewall\Panel;
14
15
use Psr\Http\Message\ResponseInterface;
16
use Shieldon\Firewall\Firewall;
17
use Shieldon\Firewall\FirewallTrait;
18
use Shieldon\Firewall\Panel\DemoTrait;
19
use Shieldon\Firewall\Utils\Container;
20
use Shieldon\Firewall\Log\ActionLogParser;
21
use function Shieldon\Firewall\__;
22
use function Shieldon\Firewall\get_request;
23
use function Shieldon\Firewall\get_response;
24
use function Shieldon\Firewall\get_session;
25
26
use PDO;
27
use PDOException;
28
use Redis;
29
use RedisException;
30
use RuntimeException;
31
use function array_push;
32
use function class_exists;
33
use function define;
34
use function defined;
35
use function extract;
36
use function file_exists;
37
use function file_put_contents;
38
use function is_array;
39
use function is_numeric;
40
use function is_string;
41
use function is_writable;
42
use function json_encode;
43
use function mkdir;
44
use function ob_end_clean;
45
use function ob_get_contents;
46
use function ob_start;
47
use function password_hash;
48
use function preg_split;
49
use function rtrim;
50
use function str_replace;
51
use function trim;
52
use function umask;
53
54
/**
55
 * User
56
 */
57
class BaseController
58
{
59
    use FirewallTrait;
60
    use DemoTrait;
61
62
    /**
63
     * LogPaeser instance.
64
     *
65
     * @var object
66
     */
67
    protected $parser;
68
69
    /**
70
     * Messages.
71
     *
72
     * @var array
73
     */
74
    protected $messages = [];
75
76
    /**
77
     * Check page availability.
78
     *
79
     * @var array
80
     */
81
    protected $pageAvailability = [
82
83
        // Need to implement Action Logger to make it true.
84
        'logs' => false,
85
    ];
86
87
    /**
88
     * see $this->csrf()
89
     *
90
     * @var array
91
     */
92
    protected $csrfField = [];
93
94
    /**
95
     * Language code.
96
     *
97
     * @var string
98
     */
99
    protected $locate = 'en';
100
101
    /**
102
     * Captcha modules.
103
     *
104
     * @var Interface
0 ignored issues
show
Bug introduced by
The type Shieldon\Firewall\Panel\Interface 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...
105
     */
106
    protected $captcha = [];
107
108
    /**
109
     * The base URL of the firewall panel.
110
     *
111
     * @var string
112
     */
113
    public $base = '';
114
115
    /**
116
     * Firewall panel base controller.                  
117
     */
118
    public function __construct() 
119
    {
120
        $firewall = Container::get('firewall');
121
122
        if (!($firewall instanceof Firewall)) {
123
            throw new RuntimeException(
124
                'The Firewall instance should be initialized first.'
125
            );
126
        }
127
128
        $this->mode          = 'managed';
129
        $this->kernel        = $firewall->getKernel();
130
        $this->configuration = $firewall->getConfiguration();
131
        $this->directory     = $firewall->getDirectory();
132
        $this->filename      = $firewall->getFilename();
133
        $this->base          = SHIELDON_PANEL_BASE;
134
135
        if (!empty($this->kernel->logger)) {
136
137
            // We need to know where the logs stored in.
138
            $logDirectory = $this->kernel->logger->getDirectory();
139
140
            // Load ActionLogParser for parsing log files.
141
            $this->parser = new ActionLogParser($logDirectory);
142
143
            $this->pageAvailability['logs'] = true;
144
        }
145
146
        $flashMessage = get_session()->get('flash_messages');
147
148
        // Flash message, use it when redirecting page.
149
        if (!empty($flashMessage)) {
150
            $this->messages = $flashMessage;
0 ignored issues
show
Documentation Bug introduced by
It seems like $flashMessage can also be of type string. However, the property $messages is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
151
            get_session()->remove('flash_messages');
152
        }
153
154
        $this->locate = 'en';
155
156
        $sessionLang = get_session()->get('shieldon_panel_lang');
157
158
        if (!empty($sessionLang)) {
159
            $this->locate = $sessionLang;
160
        }
161
    }
162
163
    /**
164
     * Load view file.
165
     *
166
     * @param string $page The page type. (filename)
167
     * @param array  $data The variables passed to that page.
168
     *
169
     * @return string
170
     */
171
    protected function loadView(string $page, array $data = []): string
172
    {
173
        if (!defined('SHIELDON_VIEW')) {
174
            define('SHIELDON_VIEW', true);
175
        }
176
177
        $viewFilePath =  __DIR__ . '/../../../templates/' . $page . '.php';
178
    
179
        if (!empty($data)) {
180
            extract($data);
181
        }
182
183
        $output = '';
184
    
185
        if (file_exists($viewFilePath)) {
186
            ob_start();
187
            require $viewFilePath;
188
            $output = ob_get_contents();
189
            ob_end_clean();
190
        }
191
192
        return $output;
193
    }
194
195
    /**
196
     * Render the web page with full layout.
197
     *
198
     * @param string $page The page type. (filename)
199
     * @param array  $data The variables passed to that page.
200
     *
201
     * @return ResponseInterface
202
     */
203
    protected function renderPage(string $page, array $data): ResponseInterface
204
    {
205
        $channelName = $this->kernel->driver->getChannel();
206
207
        if (empty($channelName)) {
208
            $channelName = 'default';
209
        }
210
211
        $body['channel_name'] = $channelName;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$body was never initialized. Although not strictly required by PHP, it is generally a good practice to add $body = array(); before regardless.
Loading history...
212
        $body['mode_name'] = $this->mode;
213
        $body['page_url'] = $this->url();
214
        $body['content'] = $this->loadView($page, $data);
215
        $body['title'] = $data['title'] ?? '';
216
217
        $body['title'] .= ' - ' . __('panel', 'title_site_wide', 'Shieldon Firewall');
218
        $body['title'] .= ' v' . SHIELDON_FIREWALL_VERSION;
219
220
        $page = $this->loadView('panel/template', $body);
221
222
        return $this->respond($page);
223
    }
224
225
    /**
226
     * Return the response instance.
227
     *
228
     * @param string $body The content body.
229
     *
230
     * @return ResponseInterface
231
     */
232
    protected function respond(string $body): ResponseInterface
233
    {
234
        $response = get_response();
235
        $stream = $response->getBody();
236
        $stream->write($body);
237
        $stream->rewind();
238
239
        return $response->withBody($stream);
240
    }
241
242
    /**
243
     * Include a view file.
244
     *
245
     * @param string $page The page type. (filename)
246
     * @param array  $data The variables passed to that page.
247
     *
248
     * @return void
249
     */
250
    protected function _include(string $page, array $data = []): void
251
    {
252
        if (!defined('SHIELDON_VIEW')) {
253
            define('SHIELDON_VIEW', true);
254
        }
255
256
        foreach ($data as $k => $v) {
257
            ${$k} = $v;
258
        }
259
260
        require __DIR__ . '/../../../templates/' . $page . '.php';
261
    }
262
263
    /**
264
     * Response message to front.
265
     *
266
     * @param string $type The message status type. error|success
267
     * @param string $text The message body.
268
     *
269
     * @return void
270
     */
271
    protected function pushMessage(string $type, string $text): void
272
    {
273
        $class = $type;
274
275
        if ($type == 'error') {
276
            $class = 'danger';
277
        }
278
279
        array_push($this->messages, [
280
            'type' => $type,
281
            'text' => $text,
282
            'class' => $class,
283
        ]);
284
    }
285
286
    /**
287
     * Return the relative URL.
288
     *
289
     * @param string $path The page's path.
290
     * @param string $tab  Tab.
291
     *
292
     * @return string
293
     */
294
    protected function url(string $path = '', string $tab = ''): string
295
    {
296
        $query = !empty($tab) ? '?tab=' . $tab : '';
297
298
        return '/' . trim($this->base, '/') . '/' . $path . '/' . $query;
299
    }
300
301
    /**
302
     * Output HTML input element with CSRF token.
303
     *
304
     * @return void
305
     */
306
    public function _csrf(): void
307
    {
308
        if (!empty($this->csrfField)) {
309
            foreach ($this->csrfField as $value) {
310
                echo '<input type="hidden" name="' . $value['name'] . '" value="' . $value['value'] . '" id="csrf-field">';
311
            }
312
        }
313
    }
314
315
    /**
316
     * Save the configuration settings to the JSON file.
317
     *
318
     * @return void
319
     */
320
    protected function saveConfig(): void
321
    {
322
        $postParams = get_request()->getParsedBody();
323
324
        $configFilePath = $this->directory . '/' . $this->filename;
325
326
        foreach ($this->csrfField as $csrfInfo) {
327
            if (!empty($csrfInfo['name'])) {
328
                unset_superglobal($csrfInfo['name'], 'post');
0 ignored issues
show
Bug introduced by
The function unset_superglobal was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

328
                /** @scrutinizer ignore-call */ 
329
                unset_superglobal($csrfInfo['name'], 'post');
Loading history...
329
            }
330
        }
331
332
        if (empty($postParams) || !is_array($postParams) || 'managed' !== $this->mode) {
333
            return;
334
        }
335
336
        $this->saveConfigPrepareSettings($postParams);
337
338
        //  Start checking the availibility of the data driver settings.
339
        $result = true;
340
        $result = $this->saveConfigCheckDataDriver($result);
341
        $result = $this->saveConfigCheckActionLogger($result);
342
        $result = $this->saveConfigCheckIptables($result);
343
344
        // Only update settings while data driver is correctly connected.
345
        if ($result) {
346
            file_put_contents($configFilePath, json_encode($this->configuration));
347
348
            $this->pushMessage('success',
349
                __(
350
                    'panel',
351
                    'success_settings_saved',
352
                    'Settings saved.'
353
                )
354
            );
355
        }
356
    }
357
358
    /**
359
     * Echo the setting string to the template.
360
     *
361
     * @param string $field   Field.
362
     * @param mixed  $defailt Default value.
363
     *
364
     * @return void
365
     */
366
    protected function _(string $field, $default = ''): void
367
    {
368
        if (is_string($this->getConfig($field)) || is_numeric($this->getConfig($field))) {
369
370
            if ('demo' === $this->mode) {
371
372
                // Hide sensitive data because of security concerns.
373
                $hiddenForDemo = [
374
                    'drivers.redis.auth',
375
                    'drivers.file.directory_path',
376
                    'drivers.sqlite.directory_path',
377
                    'drivers.mysql.dbname',
378
                    'drivers.mysql.user',
379
                    'drivers.mysql.pass',
380
                    'captcha_modules.recaptcha.config.site_key',
381
                    'captcha_modules.recaptcha.config.secret_key',
382
                    'loggers.action.config.directory_path',
383
                    'admin.user',
384
                    'admin.pass',
385
                    'admin.last_modified',
386
                    'messengers.telegram.config.api_key',
387
                    'messengers.telegram.config.channel',
388
                    'messengers.sendgrid.config.api_key',
389
                    'messengers.sendgrid.config.sender',
390
                    'messengers.sendgrid.config.recipients',
391
                    'messengers.line_notify.config.access_token',
392
                    'iptables.config.watching_folder',
393
                    'ip6tables.config.watching_folder',
394
                ];
395
396
                if (in_array($field, $hiddenForDemo)) {
397
                    echo __('panel', 'field_not_visible', 'Cannot view this field in demo mode.');
398
                } else {
399
                    echo (!empty($this->getConfig($field))) ? $this->getConfig($field) : $default;
400
                }
401
402
            } else {
403
                echo (!empty($this->getConfig($field))) ? $this->getConfig($field) : $default;
404
            }
405
        } elseif (is_array($this->getConfig($field))) {
406
407
            if ('demo' === $this->mode) {
408
                $hiddenForDemo = [
409
                    'messengers.sendgrid.config.recipients'
410
                ];
411
412
                if (in_array($field, $hiddenForDemo)) {
413
                    echo __('panel', 'field_not_visible', 'Cannot view this field in demo mode.');
414
                } else {
415
                    echo implode("\n", $this->getConfig($field));
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig($field) can also be of type string; however, parameter $pieces of implode() does only seem to accept 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

415
                    echo implode("\n", /** @scrutinizer ignore-type */ $this->getConfig($field));
Loading history...
416
                }
417
418
            } else {
419
                echo implode("\n", $this->getConfig($field));
420
            }
421
        }
422
    }
423
424
    /**
425
     * Use on HTML checkbox and radio elements.
426
     *
427
     * @param string $value
428
     * @param mixed  $valueChecked
429
     * @param bool   $isConfig
430
     *
431
     * @return void
432
     */
433
    protected function checked(string $value, $valueChecked, bool $isConfig = true): void
434
    {
435
        if ($isConfig) {
436
            if ($this->getConfig($value) === $valueChecked) {
437
                echo 'checked';
438
            } else {
439
                echo '';
440
            }
441
        } else {
442
            if ($value === $valueChecked) {
443
                echo 'checked';
444
            } else {
445
                echo '';
446
            }
447
        }
448
    }
449
450
    /**
451
     * Echo correspondence string on Messenger setting page.
452
     *
453
     * @param string $moduleName
454
     * @param string $echoType
455
     *
456
     * @return void
457
     */
458
    protected function _m(string $moduleName, string $echoType = 'css'): void
459
    {
460
        if ('css' === $echoType) {
461
            echo $this->getConfig('messengers.' . $moduleName . '.confirm_test') ? 'success' : '';
462
        }
463
464
        if ('icon' === $echoType) {
465
            echo $this->getConfig('messengers.' . $moduleName . '.confirm_test') ? '<i class="fas fa-check"></i>' : '<i class="fas fa-exclamation"></i>';
466
        }
467
    }
468
469
    /**
470
     * Use on HTML select elemets.
471
     *
472
     * @param string $value
473
     * @param mixed  $valueChecked
474
     *
475
     * @return void
476
     */
477
    protected function selected(string $value, $valueChecked): void
478
    {
479
        if ($this->getConfig($value) === $valueChecked) {
480
            echo 'selected';
481
        } else {
482
            echo '';
483
        }
484
    }
485
486
    /**
487
     * Parse the POST fields and set them into configuration data structure.
488
     * Used for saveConfig method only.
489
     *
490
     * @param array $postParams
491
     *
492
     * @return void
493
     */
494
    private function saveConfigPrepareSettings(array $postParams): void
495
    {
496
        foreach ($postParams as $postKey => $postData) {
497
            if (is_string($postData)) {
498
                if ($postData === 'on') {
499
                    $this->setConfig(str_replace('__', '.', $postKey), true);
500
501
                } elseif ($postData === 'off') {
502
                    $this->setConfig(str_replace('__', '.', $postKey), false);
503
504
                } else {
505
                    if ($postKey === 'ip_variable_source') {
506
                        $this->setConfig('ip_variable_source.REMOTE_ADDR', false);
507
                        $this->setConfig('ip_variable_source.HTTP_CF_CONNECTING_IP', false);
508
                        $this->setConfig('ip_variable_source.HTTP_X_FORWARDED_FOR', false);
509
                        $this->setConfig('ip_variable_source.HTTP_X_FORWARDED_HOST', false);
510
                        $this->setConfig('ip_variable_source.' . $postData, true);
511
512
                    } elseif ($postKey === 'dialog_ui__shadow_opacity') {
513
                        $this->setConfig('dialog_ui.shadow_opacity', (string) $postData);
514
515
                    } elseif ($postKey === 'admin__pass') {
516
                        if (strlen($postParams['admin__pass']) < 58) {
517
                            $this->setConfig('admin.pass', password_hash($postData, PASSWORD_BCRYPT));
518
                        }
519
                    } else if ($postKey === 'messengers__sendgrid__config__recipients') {
520
                        $this->setConfig(
521
                            'messengers.sendgrid.config.recipients',
522
                            preg_split('/\r\n|[\r\n]/',
523
                            $postData)
524
                        );
525
                    } else {
526
                        if (is_numeric($postData)) {
527
                            $this->setConfig(str_replace('__', '.', $postKey), (int) $postData);
528
                        } else  {
529
                            $this->setConfig(str_replace('__', '.', $postKey), $postData);
530
                        }
531
                    }
532
                }
533
            }
534
        }
535
    }
536
537
    /**
538
     * Check the settings of Action Logger.
539
     *
540
     * @return bool
541
     */
542
    private function saveConfigCheckActionLogger(bool $result): bool
543
    {
544
        if (!$result) {
545
            return false;
546
        }
547
548
        // Check Action Logger settings.
549
        $enableActionLogger = $this->getConfig('loggers.action.enable');
550
        $actionLogDir = rtrim($this->getConfig('loggers.action.config.directory_path'), '\\/ ');
551
552
        $result = true;
553
554
        if ($enableActionLogger) {
555
            if (empty($actionLogDir)) {
556
                $actionLogDir = $this->directory . '/action_logs';
557
            }
558
559
            $this->setConfig('loggers.action.config.directory_path', $actionLogDir);
560
561
            if (!is_dir($actionLogDir)) {
562
                $originalUmask = umask(0);
563
                @mkdir($actionLogDir, 0777, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

563
                /** @scrutinizer ignore-unhandled */ @mkdir($actionLogDir, 0777, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
564
                umask($originalUmask);
565
            }
566
567
            if (!is_writable($actionLogDir)) {
568
                $result = false;
569
                $this->pushMessage('error',
570
                    __(
571
                        'panel',
572
                        'error_logger_directory_not_writable',
573
                        'Action Logger requires the storage directory writable.'
574
                    )
575
                );
576
            }
577
        }
578
579
        return $result;
580
    }
581
582
    /**
583
     * Check the settings of Iptables.
584
     *
585
     * @return bool
586
     */
587
    private function saveConfigCheckIptables(bool $result): bool
588
    {
589
        if (!$result) {
590
            return false;
591
        }
592
593
        // System firewall.
594
        $enableIptables = $this->getConfig('iptables.enable');
595
        $iptablesWatchingFolder = rtrim($this->getConfig('iptables.config.watching_folder'), '\\/ ');
596
597
        $result = true;
598
599
        if ($enableIptables) {
600
            if (empty($iptablesWatchingFolder)) {
601
                $iptablesWatchingFolder = $this->directory . '/iptables';
602
            }
603
604
            $this->setConfig('iptables.config.watching_folder', $iptablesWatchingFolder);
605
606
            if (!is_dir($iptablesWatchingFolder)) {
607
                $originalUmask = umask(0);
608
                @mkdir($iptablesWatchingFolder, 0777, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

608
                /** @scrutinizer ignore-unhandled */ @mkdir($iptablesWatchingFolder, 0777, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
609
                umask($originalUmask);
610
611
                // Create default log files.
612
                if (is_writable($iptablesWatchingFolder)) {
613
                    fopen($iptablesWatchingFolder . '/iptables_queue.log', 'w+');
614
                    fopen($iptablesWatchingFolder . '/ipv4_status.log',    'w+');
615
                    fopen($iptablesWatchingFolder . '/ipv6_status.log',    'w+');
616
                    fopen($iptablesWatchingFolder . '/ipv4_command.log',   'w+');
617
                    fopen($iptablesWatchingFolder . '/ipv6_command.log',   'w+');
618
                }
619
            }
620
    
621
            if (!is_writable($iptablesWatchingFolder)) {
622
                $result = false;
623
                $this->pushMessage('error',
624
                    __(
625
                        'panel',
626
                        'error_ip6tables_directory_not_writable',
627
                        'iptables watching folder requires the storage directory writable.'
628
                    )
629
                );
630
            }
631
        }
632
633
        return $result;
634
    }
635
636
    /**
637
     * Check the settings of Data drivers.
638
     *
639
     * @return bool
640
     */
641
    protected function saveConfigCheckDataDriver(bool $result): bool
642
    {
643
        if (!$result) {
644
            return false;
645
        }
646
647
        switch ($this->configuration['driver_type']) {
648
            case 'mysql':
649
                if (class_exists('PDO')) {
650
                    $db = [
651
                        'host'    => $this->getConfig('drivers.mysql.host'),
652
                        'dbname'  => $this->getConfig('drivers.mysql.dbname'),
653
                        'user'    => $this->getConfig('drivers.mysql.user'),
654
                        'pass'    => $this->getConfig('drivers.mysql.pass'),
655
                        'charset' => $this->getConfig('drivers.mysql.charset'),
656
                    ];
657
658
                    try {
659
                        $pdo = new PDO(
0 ignored issues
show
Unused Code introduced by
The assignment to $pdo is dead and can be removed.
Loading history...
660
                            'mysql:host=' . $db['host'] . ';dbname=' . $db['dbname'] . ';charset=' . $db['charset'],
661
                            (string) $db['user'],
662
                            (string) $db['pass']
663
                        );
664
                    } catch(PDOException $e) {
665
                        $result = false;
666
                        $this->pushMessage('error', 
667
                            __(
668
                                'panel',
669
                                'error_mysql_connection',
670
                                'Cannot access to your MySQL database, please check your settings.'
671
                            )
672
                        );
673
                    }
674
                } else {
675
                    $result = false;
676
                    $this->pushMessage('error',
677
                        __(
678
                            'panel',
679
                            'error_mysql_driver_not_supported',
680
                            'Your system doesn’t support MySQL driver.'
681
                        )
682
                    );
683
                }
684
                break;
685
686
            case 'sqlite':
687
                $sqliteDir = rtrim($this->getConfig('drivers.sqlite.directory_path'), '\\/ ');
688
689
                if (empty($sqliteDir)) {
690
                    $sqliteDir = $this->directory . '/data_driver_sqlite';
691
                }
692
693
                $sqliteFilePath = $sqliteDir . '/shieldon.sqlite3';
694
                $this->setConfig('drivers.sqlite.directory_path', $sqliteDir);
695
                
696
                if (!file_exists($sqliteFilePath)) {
697
                    if (!is_dir($sqliteDir)) {
698
                        $originalUmask = umask(0);
699
                        @mkdir($sqliteDir, 0777, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

699
                        /** @scrutinizer ignore-unhandled */ @mkdir($sqliteDir, 0777, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
700
                        umask($originalUmask);
701
                    }
702
                }
703
704
                if (class_exists('PDO')) {
705
                    try {
706
                        $pdo = new PDO('sqlite:' . $sqliteFilePath);
707
                    } catch(PDOException $e) {
708
                        $result = false;
709
                        $this->pushMessage('error', $e->getMessage());
710
                    }
711
                } else {
712
                    $result = false;
713
                    $this->pushMessage('error',
714
                        __(
715
                            'panel',
716
                            'error_sqlite_driver_not_supported',
717
                            'Your system doesn’t support SQLite driver.'
718
                        )
719
                    );
720
                }
721
722
                if (!is_writable($sqliteFilePath)) {
723
                    $result = false;
724
                    $this->pushMessage('error',
725
                        __(
726
                            'panel',
727
                            'error_sqlite_directory_not_writable',
728
                            'SQLite data driver requires the storage directory writable.'
729
                        )
730
                    );
731
                }
732
                break;
733
734
            case 'redis':
735
                if (class_exists('Redis')) {
736
                    try {
737
                        $redis = new Redis();
738
                        $redis->connect(
739
                            (string) $this->getConfig('drivers.redis.host'), 
740
                            (int)    $this->getConfig('drivers.redis.port')
741
                        );
742
                    } catch(RedisException $e) {
743
                        $result = false;
744
                        $this->pushMessage('error', $e->getMessage());
745
                    }
746
                } else {
747
                    $result = false;
748
                    $this->pushMessage('error',
749
                        __(
750
                            'panel',
751
                            'error_redis_driver_not_supported',
752
                            'Your system doesn’t support Redis driver.'
753
                        )
754
                    );
755
                }
756
                break;
757
758
            case 'file':
759
            default:
760
                $fileDir = rtrim($this->getConfig('drivers.file.directory_path'), '\\/ ');
761
762
                if (empty($fileDir)) {
763
                    $fileDir = $this->directory . '/data_driver_file';
764
                    $this->setConfig('drivers.file.directory_path', $fileDir);
765
                }
766
767
                $this->setConfig('drivers.file.directory_path', $fileDir);
768
769
                if (!is_dir($fileDir)) {
770
                    $originalUmask = umask(0);
771
                    @mkdir($fileDir, 0777, true);
772
                    umask($originalUmask);
773
                }
774
775
                if (!is_writable($fileDir)) {
776
                    $result = false;
777
                    $this->pushMessage('error',
778
                        __(
779
                            'panel',
780
                            'error_file_directory_not_writable',
781
                            'File data driver requires the storage directory writable.'
782
                        )
783
                    );
784
                }
785
            // endswitch
786
        }
787
788
        return $result;
789
    }
790
}
791
792