Config.php 22.6 KB
Newer Older
1
2
3
4
5
6
7
8
<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 3/6/17
 * Time: 8:47 PM
 */

Marc Egger's avatar
Marc Egger committed
9
namespace IMATHUZH\Qfq\Core\Store;
10

11
use IMATHUZH\Qfq\Core\Exception\Thrower;
12
use IMATHUZH\Qfq\Core\Helper\HelperFile;
Marc Egger's avatar
Marc Egger committed
13
use IMATHUZH\Qfq\Core\Helper\Logger;
14
use IMATHUZH\Qfq\Core\Helper\OnArray;
15
use IMATHUZH\Qfq\Core\Helper\OnString;
16
use IMATHUZH\Qfq\Core\Helper\Path;
Marc Egger's avatar
Marc Egger committed
17
use IMATHUZH\Qfq\Core\Helper\Support;
18

19
20
21
22
/**
 * Class Config
 * @package qfq
 */
23
24
class Config {

25
26
    private static $config = null;

Marc Egger's avatar
Marc Egger committed
27
28
29
30
    const CONFIG_REQUIRED_TEMPLATE = [
        SYSTEM_DB_1_USER => null,
        SYSTEM_DB_1_PASSWORD => null,
        SYSTEM_DB_1_SERVER => "localhost",
31
        SYSTEM_DB_1_NAME => null,
Marc Egger's avatar
Marc Egger committed
32
    ];
33

34
35
36
37
38
    /**
     * Get config value with given key. Throws exception if config has not been read.
     *
     * @param string $key
     * @return mixed
39
     * @throws \CodeException
40
     * @throws \UserFormException
41
     * @throws \UserReportException
42
     */
43
    public static function get(string $key) {
44
        self::readConfig(); // only reads once
45
        return self::$config[$key] ?? null;
46
47
48
49
50
    }

    /**
     * Returns a copy of the config array. Throws exception if config has not been read.
     *
51
     * @param string $PhpUnitOverloadAbsoluteConfigFilePath
52
     * @return array
53
     * @throws \CodeException
54
     * @throws \UserFormException
55
     * @throws \UserReportException
56
     */
57
58
    public static function getConfigArray($PhpUnitOverloadAbsoluteConfigFilePath = ''): array {
        self::readConfig($PhpUnitOverloadAbsoluteConfigFilePath); // only reads once, except if argument !=''
59
60
61
62
        return self::$config;
    }

    /**
Marc Egger's avatar
Marc Egger committed
63
     * Read qfq.json (merge with Typo3-qfq config if exists).
64
     * Note: Deprecated config file typo3conf/config.qfq.php is translated to JSON in PATH:findAppToProject(..)
65
     *
66
     * @param string $PhpUnitOverloadAbsoluteConfigFilePath
67
68
69
70
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
     */
71
    private static function readConfig($PhpUnitOverloadAbsoluteConfigFilePath = '') {
72

73
        if (self::$config !== null && $PhpUnitOverloadAbsoluteConfigFilePath === '') {
74
            // only read once, except phpUnit
75
76
77
78
            return;
        }

        // read and parse config. Throw exception if not exists.
79
80
81
82
83
        $absoluteConfigFilePath = $PhpUnitOverloadAbsoluteConfigFilePath === '' ? Path::absoluteConf(CONFIG_QFQ_JSON) : $PhpUnitOverloadAbsoluteConfigFilePath;
        if (!file_exists($absoluteConfigFilePath)) {
            HelperFile::createPathRecursive(Path::absoluteConf());
            HelperFile::file_put_contents(Path::absoluteConf(CONFIG_QFQ_JSON_EXAMPLE), json_encode(self::CONFIG_REQUIRED_TEMPLATE, JSON_PRETTY_PRINT));
            Thrower::userFormException("Please create qfq config file '" . CONFIG_QFQ_JSON . "' in the conf directory which is inside the project directory. Example config file '" . CONFIG_QFQ_JSON_EXAMPLE . "' was created in conf directory.", "Project directory: " . Path::absoluteProject());
84
        }
85
        $config = HelperFile::json_decode(HelperFile::file_get_contents($absoluteConfigFilePath));
86
87
88
89

        // check required keys
        foreach (self::CONFIG_REQUIRED_TEMPLATE as $key => $value) {
            if (!array_key_exists($key, $config) || is_null($config[$key]) || $config[$key] === '') {
90
                Thrower::userFormException("Required key '$key' missing in config file " . CONFIG_QFQ_JSON, "Config file: $absoluteConfigFilePath");
91
92
93
            }
        }

94
        if ($PhpUnitOverloadAbsoluteConfigFilePath === '') {
Marc Egger's avatar
Marc Egger committed
95
            $configT3qfq = self::readTypo3QfqConfig();
96
97
98
99
100
101
102
103
104
105
106
107
108

            // Settings in qfq.json overwrite T3 settings
            $config = array_merge($configT3qfq, $config);
        }

        $config = self::renameConfigElements($config);
        $config = self::setDefaults($config);
        self::checkDeprecated($config);
        self::checkForAttack($config);

        // Copy values to detect custom settings later
        $config[F_FE_DATA_PATTERN_ERROR_SYSTEM] = $config[F_FE_DATA_PATTERN_ERROR];

109
110
111
112
113
        $config = self::adjustConfig($config);
        $config = self::setAutoConfigValue($config);

        self::checkMandatoryParameter($config);

114
115
        self::$config = $config;

116
117
        Path::setUrlApp(self::get(SYSTEM_BASE_URL));

118
119
120
121
        // Set log paths
        Path::overrideLogPathsFromConfig();
    }

122
123
124
125
126
    /**
     * Iterates over all 30 custom vars, explode them to split between key and value, append to $config.
     *
     * @param array $config
     * @return array
Marc Egger's avatar
Marc Egger committed
127
     * @throws \UserReportException
128
     */
129
    private static function getCustomVariable(array $config) {
130
131
132
133
134
135

        for ($i = 1; $i <= 30; $i++) {
            if (isset($config['custom' . $i])) {
                $arr = explode('=', $config['custom' . $i], 2);
                if (!empty($arr[0]) && !empty($arr[1])) {

136
                    $arr[0] = trim($arr[0]);
137
                    $arr[1] = OnString::trimQuote(trim($arr[1]));
138
139

                    if (isset($config[$arr[0]])) {
Marc Egger's avatar
Marc Egger committed
140
                        throw new \UserReportException("Variable '$arr[0]' already defined", ERROR_INVALID_OR_MISSING_PARAMETER);
141
142
143
144
145
146
147
148
149
150
                    }

                    $config[$arr[0]] = $arr[1];
                }
            }
        }

        return $config;
    }

151
    /**
152
     * Overwrite the qfq config file with data from given array.
153
154
155
     *
     * @param array $config
     * @throws \UserFormException
156
     * @throws \CodeException
157
     */
158
    private static function writeConfig(array $config) {
159
160
161
        $absoluteConf = Path::absoluteConf();
        HelperFile::createPathRecursive($absoluteConf);
        HelperFile::file_put_contents(Path::join($absoluteConf, CONFIG_QFQ_JSON), json_encode($config, JSON_PRETTY_PRINT));
162
163
    }

164
    /**
165
166
167
168
169
     * Replace typo3conf/config.qfq.php with fileadmin/protected/qfqProject/qfq.json
     *
     * @throws \CodeException
     * @throws \UserFormException
     */
170
    public static function migrateConfigPhpToJson(): void {
171
        // read old config.qfq.php
172
173
        $absoluteOldConfigFilePath = Path::absoluteApp(Path::APP_TO_TYPO3_CONF, CONFIG_QFQ_PHP);
        if (!is_writeable($absoluteOldConfigFilePath)) {
174
175
            throw new \UserFormException(json_encode([
                ERROR_MESSAGE_TO_USER => "Can't migrate to new config: Legacy config file `config.qfq.php` not writable.",
176
                ERROR_MESSAGE_TO_DEVELOPER => "Can't write to file/directory '$absoluteOldConfigFilePath'"]));
177
        }
178
        $config = include($absoluteOldConfigFilePath);
179

180
181
182
183
184
185
        // In case the database credentials are given in the old style: rename the keys
        $config = OnArray::renameKeys([
            SYSTEM_DB_USER => SYSTEM_DB_1_USER,
            SYSTEM_DB_SERVER => SYSTEM_DB_1_SERVER,
            SYSTEM_DB_PASSWORD => SYSTEM_DB_1_PASSWORD,
            SYSTEM_DB_NAME => SYSTEM_DB_1_NAME
186
        ], $config);
187

188
189
190
191
        // write new qfq.config.json
        self::writeConfig($config);

        // remove old
192
        HelperFile::unlink($absoluteOldConfigFilePath);
193
194
    }

195
196
197
198
199
200
201
202
    /**
     * Read Typo3-QFQ config first from global variable, then from typo3conf/Localconfig.php.
     * If both not exist, return empty array.
     *
     * @return array Empty if config not found.
     * @throws \UserFormException
     * @throws \UserReportException
     */
203
    private static function readTypo3QfqConfig(): array {
204
        $configT3qfq = array();
Marc Egger's avatar
Marc Egger committed
205
        if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][EXT_KEY])) {
206
            // Typo3 version >=9
Marc Egger's avatar
Marc Egger committed
207
208
209
210
211
            $configT3qfq = $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][EXT_KEY];
            $configT3qfq[SYSTEM_DB_NAME_T3] = self::getDbName($GLOBALS['TYPO3_CONF_VARS']['DB']);

        } elseif (isset($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][EXT_KEY])) {
            // Typo3 version <=8
212
213
214
            $configT3qfq = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][EXT_KEY]);
            $configT3qfq[SYSTEM_DB_NAME_T3] = self::getDbName($GLOBALS['TYPO3_CONF_VARS']['DB']);

215
216
217
        } elseif (is_readable(Path::absoluteApp(Path::APP_TO_TYPO3_CONF, CONFIG_T3))) {
            $absoluteTypo3ConfigFile = Path::absoluteApp(Path::APP_TO_TYPO3_CONF, CONFIG_T3);
            $configT3 = HelperFile::include($absoluteTypo3ConfigFile);
Marc Egger's avatar
Marc Egger committed
218
            if (isset($configT3['EXTENSIONS'][EXT_KEY])) {
219
                // Typo3 version >=9
Marc Egger's avatar
Marc Egger committed
220
221
222
223
224
                $configT3qfq = $configT3['EXTENSIONS'][EXT_KEY];
            } else {
                // Typo3 version <=8
                $configT3qfq = unserialize($configT3['EXT']['extConf'][EXT_KEY]);
            }
225
            if (!is_array($configT3qfq)) {
226
                Thrower::userFormException('Error read file', "Error while reading qfq config from: $absoluteTypo3ConfigFile");
227
228
229
230
231
232
233
234
            }
            $configT3qfq[SYSTEM_DB_NAME_T3] = self::getDbName($configT3['DB']);
            unset($configT3);
        }
        $configT3qfq = self::getCustomVariable($configT3qfq);
        return $configT3qfq;
    }

235
236
237
238
239
240
    /**
     * Returns T3 DB-Name, depending on T3 version
     *
     * @param array $db
     * @return mixed
     */
Carsten  Rose's avatar
Carsten Rose committed
241
    private static function getDbName(array $db) {
242
243
244
245
246

        // T3 7.x: $GLOBALS['TYPO3_CONF_VARS']['DB']['database'],  T3 8.x: $GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['dbname']
        return isset($db['database']) ? $db['database'] : $db['Connections']['Default']['dbname'];
    }

247
248
    /**
     * Checks for deprecated options.
249
     *
250
     * @param array $config
Marc Egger's avatar
Marc Egger committed
251
     * @throws \UserFormException
252
253
254
255
256
257
258
259
260
     */
    private static function checkDeprecated(array $config) {

        foreach ([SYSTEM_VAR_ADD_BY_SQL] as $key) {

            if (isset($config[$key])) {
                $msg = '';
                switch ($key) {
                    case SYSTEM_VAR_ADD_BY_SQL:
261
                        $msg = 'Replaced by: ' . SYSTEM_FILL_STORE_SYSTEM_BY_SQL . '1|2|3';
262
                }
Marc Egger's avatar
Marc Egger committed
263
                throw new \UserFormException ("Deprecated option in " . CONFIG_QFQ_PHP . ": " . SYSTEM_VAR_ADD_BY_SQL . " - " . $msg);
264
265
266
267
            }
        }
    }

268
    /**
269
270
     * Check for attack
     *
271
     * @param array $config
Marc Egger's avatar
Marc Egger committed
272
273
274
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
275
     */
276
    public static function checkForAttack(array $config) {
277
        $attack = false;
278
        $key = '';
279
        $reason = 'Problem: ';
280
281
282
283

        // Iterate over all fake vars
        $arr = explode(',', $config[SYSTEM_SECURITY_VARS_HONEYPOT]);
        foreach ($arr as $key) {
284

285
286
287
288
            $key = trim($key);
            if ($key === '') {
                continue;
            }
289
290

            if (!empty($_POST[$key])) {
291
                $attack = true;
292
                $reason .= "Post/Get Honeypot variable '$key' detected: " . htmlentities($_POST[$key]) . PHP_EOL;
293
294
295
296
297
            }
        }

        // Limit length of all get vars: protect against SQL injection based on long ...%34%34%24%34...
        $maxLength = $config[SYSTEM_SECURITY_GET_MAX_LENGTH];
298
        if ($maxLength > 0 && $attack === false) {
299
            foreach ($_GET as $key => $value) {
Carsten  Rose's avatar
Carsten Rose committed
300
301
302
303
304

                if (!is_string($value)) {
                    continue;
                }

305
306
                // Check if the variable is something like 'my_name_100' - if the part after the last '_' is numerical, this means a valid, non standard length.
                $arr = explode(GET_EXTRA_LENGTH_TOKEN, $key);
307

308
309
                $cnt = count($arr);
                if ($cnt > 1 && is_numeric($arr[$cnt - 1])) {
310
311
312
313
314
                    $maxLength = $arr[$cnt - 1];
                } else {
                    $maxLength = $config[SYSTEM_SECURITY_GET_MAX_LENGTH]; // might change again.
                }

315
316
                $len = strlen($value);
                if ($len > $maxLength) {
317
                    $attack = true;
318
                    $reason .= "Value of GET variable '$key' too long. Allowed: $maxLength, Length: $len. Value: '" . htmlentities($_GET[$key]) . "'" . PHP_EOL;
319
                }
320
321
322
323
            }
        }

        // Nothing found?
324
        if ($attack === false) {
325
326
327
            return;
        }

328
        self::attackDetectedExitNow($config, $reason);
329
330
331
    }

    /**
332
     * @param array $config
333
     * @param string $reason
Marc Egger's avatar
Marc Egger committed
334
335
336
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
337
     */
338
    public static function attackDetectedExitNow(array $config = array(), $reason = '') {
339
340

        if (count($config) == 0) {
341
            $config = self::getConfigArray();
342
343
        }

344
        Logger::logMessage(Logger::linePre() . 'Security: attack detected' . PHP_EOL . $reason, Path::absoluteQfqLogFile());
345

346
347
348
        // In case of an attack: log out the current user.
        Session::destroy();

349
350
351
352
        // Sleep
        $penalty = (empty($config[SYSTEM_SECURITY_ATTACK_DELAY]) || !is_numeric($config[SYSTEM_SECURITY_ATTACK_DELAY])) ?
            SYSTEM_SECURITY_ATTACK_DELAY_DEFAULT : $config[SYSTEM_SECURITY_ATTACK_DELAY];

Carsten  Rose's avatar
Carsten Rose committed
353
354
355
        if (!defined('PHPUNIT_QFQ')) {
            sleep($penalty);
        }
356

357
        if ($config[SYSTEM_SECURITY_SHOW_MESSAGE] == 'true' || $config[SYSTEM_SECURITY_SHOW_MESSAGE] == 1) {
358

359
            echo "Attack detected - stop process <p>" . $reason . '</p>';
360
361
362
363
364
365
366
//            $answer[API_STATUS] = API_ANSWER_STATUS_ERROR;
//            $answer[API_MESSAGE] = 'Attack detected - stop process.';
//            if($getParamName!='') {
//                $answer[API_MESSAGE] .= " Attack parameter: $getParamName";
//            }
//            header("Content-Type: application/json");
//            echo json_encode($answer);
367
368
        }

369
        if (defined('PHPUNIT_QFQ')) {
Marc Egger's avatar
Marc Egger committed
370
            throw new \UserFormException('Attack detected', 1);
371
372
        }

373
374
375
376
377
        exit;
    }

    /**
     * @param array $config
Carsten  Rose's avatar
Carsten Rose committed
378
     *
379
380
     * @return array
     */
381
    public static function setDefaults(array $config) {
382
383
384

        $default = [

385
            SYSTEM_DB_INIT => 'set names utf8',
386
387
            SYSTEM_DB_INDEX_DATA => DB_INDEX_DEFAULT,
            SYSTEM_DB_INDEX_QFQ => DB_INDEX_DEFAULT,
388

389
            SYSTEM_RENDER => SYSTEM_RENDER_SINGLE,
390
391
            SYSTEM_DATE_FORMAT => 'yyyy-mm-dd',
            SYSTEM_SHOW_DEBUG_INFO => SYSTEM_SHOW_DEBUG_INFO_AUTO,
392
            SYSTEM_REPORT_MIN_PHP_VERSION => SYSTEM_REPORT_MIN_PHP_VERSION_AUTO,
393
394
395
            SYSTEM_MAIL_LOG_PATHFILENAME => '',
            SYSTEM_QFQ_LOG_PATHFILENAME => '',
            SYSTEM_SQL_LOG_PATHFILENAME => '',
396
            SYSTEM_SQL_LOG_MODE => 'modify',
397
            SYSTEM_SQL_LOG_MODE_AUTOCRON => 'error',
398
399
400
401
            F_BS_COLUMNS => 'col-md-12 col-lg-10',
            F_BS_LABEL_COLUMNS => 'col-md-3 col-lg-3',
            F_BS_INPUT_COLUMNS => 'col-md-6 col-lg-6',
            F_BS_NOTE_COLUMNS => 'col-md-3 col-lg-3',
402

403
404
            F_CLASS => 'qfq-notify',

405
406
407
408
            F_CLASS_PILL => 'qfq-color-grey-1',
            F_CLASS_BODY => 'qfq-color-grey-2',

            F_SAVE_BUTTON_TEXT => '',
409
            F_SAVE_BUTTON_TOOLTIP => '',
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
            F_SAVE_BUTTON_CLASS => 'btn btn-default navbar-btn',
            F_SAVE_BUTTON_GLYPH_ICON => GLYPH_ICON_CHECK,

            F_CLOSE_BUTTON_TEXT => '',
            F_CLOSE_BUTTON_TOOLTIP => 'Close',
            F_CLOSE_BUTTON_CLASS => 'btn btn-default navbar-btn',
            F_CLOSE_BUTTON_GLYPH_ICON => GLYPH_ICON_CLOSE,

            F_DELETE_BUTTON_TEXT => '',
            F_DELETE_BUTTON_TOOLTIP => 'Delete',
            F_DELETE_BUTTON_CLASS => 'btn btn-default navbar-btn',
            F_DELETE_BUTTON_GLYPH_ICON => GLYPH_ICON_DELETE,

            F_NEW_BUTTON_TEXT => '',
            F_NEW_BUTTON_TOOLTIP => 'New',
            F_NEW_BUTTON_CLASS => 'btn btn-default navbar-btn',
            F_NEW_BUTTON_GLYPH_ICON => GLYPH_ICON_NEW,

            F_BUTTON_ON_CHANGE_CLASS => 'btn-info alert-info',
            SYSTEM_EDIT_FORM_PAGE => 'form',
430
            SYSTEM_SECURITY_VARS_HONEYPOT => SYSTEM_SECURITY_VARS_HONEYPOT_NAMES,
431
432
433
            SYSTEM_SECURITY_ATTACK_DELAY => SYSTEM_SECURITY_ATTACK_DELAY_DEFAULT,
            SYSTEM_SECURITY_SHOW_MESSAGE => '0',
            SYSTEM_SECURITY_GET_MAX_LENGTH => SYSTEM_SECURITY_GET_MAX_LENGTH_DEFAULT,
434
435
436

            SYSTEM_LABEL_ALIGN => SYSTEM_LABEL_ALIGN_LEFT,

437
            SYSTEM_ESCAPE_TYPE_DEFAULT => TOKEN_ESCAPE_MYSQL,
438
439
            SYSTEM_EXTRA_BUTTON_INFO_INLINE => '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>',
            SYSTEM_EXTRA_BUTTON_INFO_BELOW => '<span class="glyphicon glyphicon-info-sign text-info" aria-hidden="true"></span>',
440
441
442
443
444
            SYSTEM_EXTRA_BUTTON_INFO_CLASS => '',

            SYSTEM_DB_UPDATE => SYSTEM_DB_UPDATE_AUTO,
            SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS => SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS_DEFAULT,

445
            SYSTEM_SESSION_TIMEOUT_SECONDS => Session::getPhpSessionTimeout(),
446

447
            SYSTEM_DOCUMENTATION_QFQ => SYSTEM_DOCUMENTATION_QFQ_URL,
448
449
            SYSTEM_ENTER_AS_SUBMIT => 1,

450
            SYSTEM_CMD_WKHTMLTOPDF => '/opt/wkhtmltox/bin/wkhtmltopdf',
451
452
            SYSTEM_CMD_INKSCAPE => 'inkscape',
            SYSTEM_CMD_CONVERT => 'convert',
453
454
            SYSTEM_CMD_PDF2SVG => 'pdf2svg',
            SYSTEM_CMD_PDFTOCAIRO => 'pdftocairo',
455
456
457
            SYSTEM_CMD_QPDF => 'qpdf',
            SYSTEM_CMD_GS => 'gs',
            SYSTEM_CMD_PDFUNITE => 'pdfunite',
458
            SYSTEM_CMD_IMG2PDF => 'img2pdf',
459

460
461
            SYSTEM_THUMBNAIL_DIR_SECURE_REL_TO_APP => Path::APP_TO_SYSTEM_THUMBNAIL_DIR_SECURE_DEFAULT,
            SYSTEM_THUMBNAIL_DIR_PUBLIC_REL_TO_APP => Path::APP_TO_SYSTEM_THUMBNAIL_DIR_PUBLIC_DEFAULT,
462

463
            F_FE_DATA_REQUIRED_ERROR => F_FE_DATA_REQUIRED_ERROR_DEFAULT,
464
            F_FE_DATA_MATCH_ERROR => F_FE_DATA_MATCH_ERROR_DEFAULT,
465
            F_FE_DATA_ERROR => F_FE_DATA_ERROR_DEFAULT,
466
            F_FE_DATA_PATTERN_ERROR => F_FE_DATA_PATTERN_ERROR_DEFAULT,
467
468
469

            SYSTEM_FLAG_PRODUCTION => 'yes',
            SYSTEM_THROW_GENERAL_ERROR => 'auto',
Carsten  Rose's avatar
Carsten Rose committed
470
471

            SYSTEM_SECURITY_FAILED_AUTH_DELAY => '3',
472
473
474

            SYSTEM_FILE_MAX_FILE_SIZE => min(Support::returnBytes(ini_get('post_max_size')), Support::returnBytes(ini_get('upload_max_filesize'))),

475
476
        ];

477
478
479
480
481
482
483
        foreach ($default as $key => $value) {
            if (!isset($config[$key]) || $config[$key] == '') {
                $config[$key] = $value;
            }
        }

        return $config;
484
485
    }

486

487
488
    /**
     * Rename Elements defined in config.qfq.ini to more appropriate in user interaction.
Carsten  Rose's avatar
Carsten Rose committed
489
490
     * E.g.: in config.qfq.ini everything is in upper case and word space is '_'. In Form.parameter it's lowercase and
     * camel hook.
491
492
     *
     * @param array $config
Carsten  Rose's avatar
Carsten Rose committed
493
     *
494
495
496
497
498
499
     * @return array
     */
    private static function renameConfigElements(array $config) {

        // oldname > newname
        $setting = [
500
            [SYSTEM_FORM_BS_COLUMNS, F_BS_COLUMNS],
501
502
503
            [SYSTEM_FORM_BS_LABEL_COLUMNS, F_BS_LABEL_COLUMNS],
            [SYSTEM_FORM_BS_INPUT_COLUMNS, F_BS_INPUT_COLUMNS],
            [SYSTEM_FORM_BS_NOTE_COLUMNS, F_BS_NOTE_COLUMNS],
504

505
506
507
508
            [SYSTEM_FORM_DATA_PATTERN_ERROR, F_FE_DATA_PATTERN_ERROR],
            [SYSTEM_FORM_DATA_REQUIRED_ERROR, F_FE_DATA_REQUIRED_ERROR],
            [SYSTEM_FORM_DATA_MATCH_ERROR, F_FE_DATA_MATCH_ERROR],
            [SYSTEM_FORM_DATA_ERROR, F_FE_DATA_ERROR],
509

510
511
512
            [SYSTEM_CSS_CLASS_QFQ_FORM, F_CLASS],
            [SYSTEM_CSS_CLASS_QFQ_FORM_PILL, F_CLASS_PILL],
            [SYSTEM_CSS_CLASS_QFQ_FORM_BODY, F_CLASS_BODY],
513
            [SYSTEM_SAVE_BUTTON_CLASS_ON_CHANGE, F_BUTTON_ON_CHANGE_CLASS],
514

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
        ];

        foreach ($setting as $row) {
            $oldName = $row[0];
            $newName = $row[1];

            if (isset($config[$oldName])) {
                $config[$newName] = $config[$oldName];
                if ($oldName != $newName) {
                    unset($config[$oldName]);
                }
            }
        }

        return $config;
    }
531
532
533
534
535
536
537
538
539

    /**
     * Depending on some configuration value, update corresponding values.
     *
     * @param array $config
     * @return array
     */
    private static function adjustConfig(array $config) {

540
        $config[SYSTEM_SHOW_DEBUG_INFO] = self::adjustConfigDebugInfoAuto($config[SYSTEM_SHOW_DEBUG_INFO], T3Info::beUserLoggedIn());
541
542
543
        if ($config[SYSTEM_REPORT_MIN_PHP_VERSION] == SYSTEM_REPORT_MIN_PHP_VERSION_AUTO && T3Info::beUserLoggedIn()) {
            $config[SYSTEM_REPORT_MIN_PHP_VERSION] = SYSTEM_REPORT_MIN_PHP_VERSION_YES;
        }
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605

        // In case the database credentials are given in the old style: copy them to the new style
        if (!isset($config[SYSTEM_DB_1_USER]) && isset($config[SYSTEM_DB_USER])) {
            $config[SYSTEM_DB_1_USER] = $config[SYSTEM_DB_USER];
            $config[SYSTEM_DB_1_SERVER] = $config[SYSTEM_DB_SERVER];
            $config[SYSTEM_DB_1_PASSWORD] = $config[SYSTEM_DB_PASSWORD];
            $config[SYSTEM_DB_1_NAME] = $config[SYSTEM_DB_NAME];
        }

        if ($config[SYSTEM_THROW_GENERAL_ERROR] == 'auto') {
            $config[SYSTEM_THROW_GENERAL_ERROR] = $config[SYSTEM_FLAG_PRODUCTION] == 'yes' ? 'no' : 'yes';
        }

        return $config;
    }

    /**
     * @param string $value
     *
     * @param $flag
     * @return string
     */
    public static function adjustConfigDebugInfoAuto($value, $flag) {

        // Check if SHOW_DEBUG_INFO contains 'auto'. Replace with appropriate.
        if (Support::findInSet(SYSTEM_SHOW_DEBUG_INFO_AUTO, $value) && $flag) {
            $value = str_replace(SYSTEM_SHOW_DEBUG_INFO_AUTO, SYSTEM_SHOW_DEBUG_INFO_YES, $value);
        }

        return $value;
    }

    /**
     * Set automatic filled values
     *
     * @param array $config
     * @return array
     */
    private static function setAutoConfigValue(array $config) {

        $config[SYSTEM_DB_NAME_DATA] = $config['DB_' . $config[SYSTEM_DB_INDEX_DATA] . '_NAME'] ?? '';
        $config[SYSTEM_DB_NAME_QFQ] = $config['DB_' . $config[SYSTEM_DB_INDEX_QFQ] . '_NAME'] ?? '';

        return $config;
    }

    /**
     * Iterate over all Parameter which have to exist in the config. Throw an array if any is missing.
     *
     * @param array $config
     *
     * @throws \UserFormException
     */
    private static function checkMandatoryParameter(array $config) {

        // Check mandatory config vars.
        $names = array_merge([SYSTEM_SQL_LOG_MODE],
            self::dbCredentialName($config[SYSTEM_DB_INDEX_DATA]),
            self::dbCredentialName($config[SYSTEM_DB_INDEX_QFQ]));

        foreach ($names as $name) {
            if (!isset($config[$name])) {
606
                throw new \UserFormException ("Missing configuration in `" . CONFIG_QFQ_JSON . "`: $name", ERROR_MISSING_CONFIG_INI_VALUE);
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
            }
        }
    }

    /**
     * @param $index
     * @return array
     */
    private static function dbCredentialName($index) {
        $names = array();
        $names[] = 'DB_' . $index . '_USER';
        $names[] = 'DB_' . $index . '_SERVER';
        $names[] = 'DB_' . $index . '_PASSWORD';
        $names[] = 'DB_' . $index . '_NAME';

        return $names;
    }
624
}