Lines 96.66% 29 / 30
Methods 75.00% 3 / 4
Classes 0.00% 0 / 1
Covered by tests of size
Name Lines Methods CRAP
 fixIncludePath 100.00% 3 / 3 100.00% 1 / 1 2
 configurePcre 100.00% 2 / 2 100.00% 1 / 1 1
 registerErrorHandlers 100.00% 2 / 2 100.00% 1 / 1 1
 configureSession 95.65% 22 / 23 0.00% 0 / 1 7
26class PhpConfigurator
27{
28    /** @var null|callable(string): void */
29    private static $redisConfigurator = [RedisSessionHandler::class, 'configure'];
30
31    /**
32     * Ensures '.' is in the PHP include path.
33     */
34    public static function fixIncludePath(): void
35    {
36        $includePaths = explode(PATH_SEPARATOR, (string) ini_get('include_path'));
37        if (!in_array('.', $includePaths, strict: true)) {
38            set_include_path('.' . PATH_SEPARATOR . (string) get_include_path());
39        }
40    }
41
42    /**
43     * Increases PCRE limits to handle large content.
44     */
45    /* @mago-expect lint:no-ini-set - this bootstrap class is the single place that configures PHP runtime settings */
46    public static function configurePcre(): void
47    {
48        ini_set('pcre.backtrack_limit', value: '100000000');
49        ini_set('pcre.recursion_limit', value: '100000000');
50    }
51
52    /**
53     * Registers the phpMyFAQ error and exception handlers.
54     */
55    public static function registerErrorHandlers(): void
56    {
57        set_error_handler(\phpMyFAQ\Core\Error::errorHandler(...));
58        set_exception_handler(\phpMyFAQ\Core\Error::exceptionHandler(...));
59    }
60
61    /**
62     * Configures secure session settings if no session is active yet.
63     */
64    /* @mago-expect lint:no-ini-set - this bootstrap class is the single place that configures PHP runtime settings */
65    public static function configureSession(?Configuration $configuration = null): void
66    {
67        if (session_status() !== PHP_SESSION_ACTIVE) {
68            ini_set('session.use_only_cookies', value: '1');
69            ini_set('session.use_trans_sid', value: '0');
70            ini_set('session.cookie_samesite', value: 'Strict');
71            ini_set('session.cookie_httponly', value: '1');
72            ini_set('session.cookie_secure', value: '1');
73
74            $sessionSavePath = trim((string) ($configuration?->get('session.savePath') ?? ''));
75
76            if ($sessionSavePath !== '') {
77                ini_set('session.save_path', $sessionSavePath);
78            }
79
80            $sessionHandler = strtolower((string) ($configuration?->get('session.handler') ?? 'files'));
81            $redisDsn = trim((string) ($configuration?->get('session.redisDsn') ?? ''));
82
83            switch ($sessionHandler) {
84                case 'files':
85                    ini_set('session.save_handler', value: 'files');
86                    break;
87                case 'redis':
88                    if (self::$redisConfigurator === null) {
89                        throw new RuntimeException('No Redis session configurator is registered.');
90                    }
91
92                    call_user_func(self::$redisConfigurator, $redisDsn);
93                    break;
94                default:
95                    throw new RuntimeException(sprintf(
96                        'Unsupported session handler "%s". Allowed values: files, redis.',
97                        $sessionHandler,
98                    ));
99            }
100        }
101    }
102}