FormDisplay::displayFieldInput()   F
last analyzed

Complexity

Conditions 31
Paths 2584

Size

Total Lines 138
Code Lines 96

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 992

Importance

Changes 0
Metric Value
cc 31
eloc 96
nc 2584
nop 7
dl 0
loc 138
ccs 0
cts 96
cp 0
crap 992
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Form management class, displays and processes forms
4
 *
5
 * Explanation of used terms:
6
 * o work_path - original field path, eg. Servers/4/verbose
7
 * o system_path - work_path modified so that it points to the first server,
8
 *                 eg. Servers/1/verbose
9
 * o translated_path - work_path modified for HTML field name, a path with
10
 *                     slashes changed to hyphens, eg. Servers-4-verbose
11
 */
12
13
declare(strict_types=1);
14
15
namespace PhpMyAdmin\Config;
16
17
use PhpMyAdmin\Config;
18
use PhpMyAdmin\Config\Forms\User\UserFormList;
19
use PhpMyAdmin\Error\ErrorHandler;
20
use PhpMyAdmin\Html\MySQLDocumentation;
21
use PhpMyAdmin\Util;
22
23
use function __;
24
use function array_flip;
25
use function array_keys;
26
use function array_search;
27
use function explode;
28
use function function_exists;
29
use function gettype;
30
use function implode;
31
use function is_array;
32
use function is_bool;
33
use function is_numeric;
34
use function mb_substr;
35
use function preg_match;
36
use function settype;
37
use function sprintf;
38
use function str_ends_with;
39
use function str_replace;
40
use function str_starts_with;
41
use function trim;
42
43
/**
44
 * Form management class, displays and processes forms
45
 */
46
class FormDisplay
47
{
48
    /**
49
     * Form list
50
     *
51
     * @var array<string, Form>
52
     */
53
    private array $forms = [];
54
55
    /**
56
     * Stores validation errors, indexed by paths
57
     * [ Form_name ] is an array of form errors
58
     * [path] is a string storing error associated with single field
59
     *
60
     * @var mixed[]
61
     */
62
    private array $errors = [];
63
64
    /**
65
     * Paths changed so that they can be used as HTML ids, indexed by paths
66
     *
67
     * @var mixed[]
68
     */
69
    private array $translatedPaths = [];
70
71
    /**
72
     * Server paths change indexes so we define maps from current server
73
     * path to the first one, indexed by work path
74
     *
75
     * @var mixed[]
76
     */
77
    private array $systemPaths = [];
78
79
    /**
80
     * Tells whether forms have been validated
81
     */
82
    private bool $isValidated = true;
83
84
    /**
85
     * Dictionary with user preferences keys
86
     */
87
    private array|null $userprefsKeys = null;
88
89
    /**
90
     * Dictionary with disallowed user preferences keys
91
     *
92
     * @var mixed[]
93
     */
94
    private array $userprefsDisallow = [];
95
96
    private FormDisplayTemplate $formDisplayTemplate;
97
98
    private bool $isSetupScript;
99
100
    private static bool $hasCheckPageRefresh = false;
101
102 40
    public function __construct(private ConfigFile $configFile)
103
    {
104 40
        $config = Config::getInstance();
0 ignored issues
show
Deprecated Code introduced by
The function PhpMyAdmin\Config::getInstance() has been deprecated: Use dependency injection instead. ( Ignorable by Annotation )

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

104
        $config = /** @scrutinizer ignore-deprecated */ Config::getInstance();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
105 40
        $this->formDisplayTemplate = new FormDisplayTemplate($config);
106 40
        $this->isSetupScript = $config->isSetup();
107
        // initialize validators
108 40
        Validator::getValidators($this->configFile);
109
    }
110
111
    /**
112
     * Returns {@link ConfigFile} associated with this instance
113
     */
114
    public function getConfigFile(): ConfigFile
115
    {
116
        return $this->configFile;
117
    }
118
119
    /**
120
     * Registers form in form manager
121
     *
122
     * @param string   $formName Form name
123
     * @param mixed[]  $form     Form data
124
     * @param int|null $serverId 0 if new server, validation; >= 1 if editing a server
125
     */
126 4
    public function registerForm(string $formName, array $form, int|null $serverId = null): void
127
    {
128 4
        $this->forms[$formName] = new Form($formName, $form, $this->configFile, $serverId);
129 4
        $this->isValidated = false;
130 4
        foreach ($this->forms[$formName]->fields as $path) {
131 4
            $workPath = $serverId === null
132
                ? $path
133 4
                : str_replace('Servers/1/', 'Servers/' . $serverId . '/', $path);
134 4
            $this->systemPaths[$workPath] = $path;
135 4
            $this->translatedPaths[$workPath] = str_replace('/', '-', $workPath);
136
        }
137
    }
138
139
    /**
140
     * Processes forms, returns true on successful save
141
     *
142
     * @param bool $allowPartialSave allows for partial form saving
143
     *                               on failed validation
144
     * @param bool $checkFormSubmit  whether check for $_POST['submit_save']
145
     */
146 4
    public function process(bool $allowPartialSave = true, bool $checkFormSubmit = true): bool
147
    {
148 4
        if ($checkFormSubmit && ! isset($_POST['submit_save'])) {
149 4
            return false;
150
        }
151
152
        // save forms
153 4
        if ($this->forms !== []) {
154 4
            return $this->save(array_keys($this->forms), $allowPartialSave);
155
        }
156
157 4
        return false;
158
    }
159
160
    /**
161
     * Runs validation for all registered forms
162
     */
163 8
    private function validate(): void
164
    {
165 8
        if ($this->isValidated) {
166 8
            return;
167
        }
168
169
        $paths = [];
170
        $values = [];
171
        foreach ($this->forms as $form) {
172
            $paths[] = $form->name;
173
            // collect values and paths
174
            foreach ($form->fields as $path) {
175
                $workPath = array_search($path, $this->systemPaths);
176
                $values[$path] = $this->configFile->getValue($workPath);
177
                $paths[] = $path;
178
            }
179
        }
180
181
        // run validation
182
        $errors = Validator::validate($this->configFile, $paths, $values, false);
183
184
        // change error keys from canonical paths to work paths
185
        if (is_array($errors) && $errors !== []) {
186
            $this->errors = [];
187
            foreach ($errors as $path => $errorList) {
188
                $workPath = array_search($path, $this->systemPaths);
189
                // field error
190
                if (! $workPath) {
191
                    // form error, fix path
192
                    $workPath = $path;
193
                }
194
195
                $this->errors[$workPath] = $errorList;
196
            }
197
        }
198
199
        $this->isValidated = true;
200
    }
201
202
    /**
203
     * Outputs HTML for forms
204
     *
205
     * @param bool    $showButtons  whether show submit and reset button
206
     * @param string  $formAction   action attribute for the form
207
     * @param mixed[] $hiddenFields array of form hidden fields (key: field
208
     *                                 name)
209
     *
210
     * @return string HTML for forms
211
     */
212
    public function getDisplay(
213
        bool $showButtons = true,
214
        string $formAction = '',
215
        array $hiddenFields = [],
216
    ): string {
217
        $fieldValidators = [];
218
        $defaultValues = [];
219
220
        /**
221
         * We do validation on page refresh when browser remembers field values,
222
         * add a field with known value which will be used for checks.
223
         */
224
        if (! self::$hasCheckPageRefresh) {
225
            self::$hasCheckPageRefresh = true;
226
        }
227
228
        $tabs = [];
229
        foreach ($this->forms as $form) {
230
            $tabs[$form->name] = Descriptions::get('Form_' . $form->name);
231
        }
232
233
        // validate only when we aren't displaying a "new server" form
234
        $isNewServer = false;
235
        foreach ($this->forms as $form) {
236
            if ($form->index === 0) {
237
                $isNewServer = true;
238
                break;
239
            }
240
        }
241
242
        if (! $isNewServer) {
243
            $this->validate();
244
        }
245
246
        // user preferences
247
        $this->loadUserprefsInfo();
248
249
        $validators = Validator::getValidators($this->configFile);
250
        $forms = [];
251
252
        foreach ($this->forms as $key => $form) {
253
            $this->formDisplayTemplate->group = 0;
254
            $forms[$key] = [
255
                'name' => $form->name,
256
                'descriptions' => [
257
                    'name' => Descriptions::get('Form_' . $form->name),
258
                    'desc' => Descriptions::get('Form_' . $form->name, 'desc'),
259
                ],
260
                'errors' => $this->errors[$form->name] ?? null,
261
                'fields_html' => '',
262
            ];
263
264
            foreach ($form->fields as $field => $path) {
265
                $workPath = array_search($path, $this->systemPaths);
266
                $translatedPath = $this->translatedPaths[$workPath];
267
                // always true/false for user preferences display
268
                // otherwise null
269
                $userPrefsAllow = isset($this->userprefsKeys[$path])
270
                    ? ! isset($this->userprefsDisallow[$path])
271
                    : null;
272
                // display input
273
                $forms[$key]['fields_html'] .= $this->displayFieldInput(
274
                    $form,
275
                    $field,
276
                    $path,
277
                    $workPath,
278
                    $translatedPath,
279
                    $userPrefsAllow,
280
                    $defaultValues,
281
                );
282
                // register JS validators for this field
283
                if (! isset($validators[$path])) {
284
                    continue;
285
                }
286
287
                $this->formDisplayTemplate->addJsValidate($translatedPath, $validators[$path], $fieldValidators);
288
            }
289
        }
290
291
        return $this->formDisplayTemplate->display([
292
            'action' => $formAction,
293
            'has_check_page_refresh' => self::$hasCheckPageRefresh,
294
            'hidden_fields' => $hiddenFields,
295
            'tabs' => $tabs,
296
            'forms' => $forms,
297
            'show_buttons' => $showButtons,
298
            'default_values' => $defaultValues,
299
            'field_validators' => $fieldValidators,
300
        ]);
301
    }
302
303
    /**
304
     * Prepares data for input field display and outputs HTML code
305
     *
306
     * @param string    $field          field name as it appears in $form
307
     * @param string    $systemPath     field path, eg. Servers/1/verbose
308
     * @param string    $workPath       work path, eg. Servers/4/verbose
309
     * @param string    $translatedPath work path changed so that it can be
310
     *                                  used as XHTML id
311
     *                                  besides the input field
312
     * @param bool|null $userPrefsAllow whether user preferences are enabled
313
     *                                  for this field (null - no support,
314
     *                                  true/false - enabled/disabled)
315
     * @param mixed[]   $jsDefault      array which stores JavaScript code
316
     *                                to be displayed
317
     *
318
     * @return string|null HTML for input field
319
     */
320
    private function displayFieldInput(
321
        Form $form,
322
        string $field,
323
        string $systemPath,
324
        string $workPath,
325
        string $translatedPath,
326
        bool|null $userPrefsAllow,
327
        array &$jsDefault,
328
    ): string|null {
329
        $name = Descriptions::get($systemPath);
330
        $description = Descriptions::get($systemPath, 'desc');
331
332
        $value = $this->configFile->get($workPath);
333
        $valueDefault = $this->configFile->getDefault($systemPath);
334
        $valueIsDefault = false;
335
        if ($value === null || $value === $valueDefault) {
336
            $value = $valueDefault;
337
            $valueIsDefault = true;
338
        }
339
340
        $opts = [
341
            'doc' => $this->getDocLink($systemPath),
342
            'show_restore_default' => true,
343
            'userprefs_allow' => $userPrefsAllow,
344
            'userprefs_comment' => Descriptions::get($systemPath, 'cmt'),
345
        ];
346
        if (isset($form->default[$systemPath])) {
347
            $opts['setvalue'] = (string) $form->default[$systemPath];
348
        }
349
350
        if (isset($this->errors[$workPath])) {
351
            $opts['errors'] = $this->errors[$workPath];
352
        }
353
354
        $type = '';
355
        switch ($form->getOptionType($field)) {
356
            case 'string':
357
                $type = 'text';
358
                break;
359
            case 'short_string':
360
                $type = 'short_text';
361
                break;
362
            case 'double':
363
            case 'integer':
364
                $type = 'number_text';
365
                break;
366
            case 'boolean':
367
                $type = 'checkbox';
368
                break;
369
            case 'select':
370
                $type = 'select';
371
                $opts['values'] = $form->getOptionValueList($form->fields[$field]);
372
                break;
373
            case 'array':
374
                $type = 'list';
375
                $value = (array) $value;
376
                $valueDefault = (array) $valueDefault;
377
                break;
378
            case 'group':
379
                // :group:end is changed to :group:end:{unique id} in Form class
380
                $htmlOutput = '';
381
                if (mb_substr($field, 7, 4) !== 'end:') {
382
                    $htmlOutput .= $this->formDisplayTemplate->displayGroupHeader(
383
                        mb_substr($field, 7),
384
                    );
385
                } else {
386
                    $this->formDisplayTemplate->displayGroupFooter();
387
                }
388
389
                return $htmlOutput;
390
391
            case 'NULL':
392
                ErrorHandler::getInstance()->addUserError('Field ' . $systemPath . ' has no type');
393
394
                return null;
395
        }
396
397
        // detect password fields
398
        if (
399
            $type === 'text'
400
            && (str_ends_with($translatedPath, '-password')
401
               || str_ends_with($translatedPath, 'pass')
402
               || str_ends_with($translatedPath, 'Pass'))
403
        ) {
404
            $type = 'password';
405
        }
406
407
        // TrustedProxies requires changes before displaying
408
        if ($systemPath === 'TrustedProxies') {
409
            foreach ($value as $ip => &$v) {
410
                if (preg_match('/^-\d+$/', $ip) === 1) {
411
                    continue;
412
                }
413
414
                $v = $ip . ': ' . $v;
415
            }
416
        }
417
418
        $this->setComments($systemPath, $opts);
419
420
        // send default value to form's JS
421
        $jsLine = '';
422
        switch ($type) {
423
            case 'text':
424
            case 'short_text':
425
            case 'number_text':
426
            case 'password':
427
                $jsLine = (string) $valueDefault;
428
                break;
429
            case 'checkbox':
430
                $jsLine = (bool) $valueDefault;
431
                break;
432
            case 'select':
433
                $valueDefaultJs = is_bool($valueDefault)
434
                ? (int) $valueDefault
435
                : $valueDefault;
436
                $jsLine = (array) $valueDefaultJs;
437
                break;
438
            case 'list':
439
                $val = $valueDefault;
440
                if (isset($val['wrapper_params'])) {
441
                    unset($val['wrapper_params']);
442
                }
443
444
                $jsLine = implode("\n", $val);
445
                break;
446
        }
447
448
        $jsDefault[$translatedPath] = $jsLine;
449
450
        return $this->formDisplayTemplate->displayInput(
451
            $translatedPath,
452
            $name,
453
            $type,
454
            $value,
455
            $description,
456
            $valueIsDefault,
457
            $opts,
458
        );
459
    }
460
461
    /**
462
     * Displays errors
463
     *
464
     * @return string HTML for errors
465
     */
466 4
    public function displayErrors(): string
467
    {
468 4
        $this->validate();
469
470 4
        $htmlOutput = '';
471
472 4
        foreach ($this->errors as $systemPath => $errorList) {
473 4
            if (isset($this->systemPaths[$systemPath])) {
474 4
                $name = Descriptions::get($this->systemPaths[$systemPath]);
475
            } else {
476 4
                $name = Descriptions::get('Form_' . $systemPath);
477
            }
478
479 4
            $htmlOutput .= $this->formDisplayTemplate->displayErrors($name, $errorList);
480
        }
481
482 4
        return $htmlOutput;
483
    }
484
485
    /**
486
     * Reverts erroneous fields to their default values
487
     */
488 4
    public function fixErrors(): void
489
    {
490 4
        $this->validate();
491 4
        if ($this->errors === []) {
492 4
            return;
493
        }
494
495 4
        foreach (array_keys($this->errors) as $workPath) {
496 4
            if (! isset($this->systemPaths[$workPath])) {
497 4
                continue;
498
            }
499
500 4
            $canonicalPath = $this->systemPaths[$workPath];
501 4
            $this->configFile->set($workPath, $this->configFile->getDefault($canonicalPath));
502
        }
503
    }
504
505
    /**
506
     * Validates select field and casts $value to correct type
507
     *
508
     * @param string|bool $value   Current value
509
     * @param mixed[]     $allowed List of allowed values
510
     */
511 4
    private function validateSelect(string|bool &$value, array $allowed): bool
512
    {
513 4
        $valueCmp = is_bool($value)
514
            ? (int) $value
515 4
            : $value;
516 4
        foreach (array_keys($allowed) as $vk) {
517
            // equality comparison only if both values are numeric or not numeric
518
            // (allows to skip 0 == 'string' equalling to true)
519
            // or identity (for string-string)
520 4
            if (! ($vk == $value && ! (is_numeric($valueCmp) xor is_numeric($vk))) && $vk !== $value) {
521 4
                continue;
522
            }
523
524
            // keep boolean value as boolean
525 4
            if (! is_bool($value)) {
526
                // phpcs:ignore Generic.PHP.ForbiddenFunctions
527 4
                settype($value, gettype($vk));
528
            }
529
530 4
            return true;
531
        }
532
533 4
        return false;
534
    }
535
536
    /**
537
     * Validates and saves form data to session
538
     *
539
     * @param string[] $forms            List of form names.
540
     * @param bool     $allowPartialSave Allows for partial form saving on failed validation.
541
     */
542
    public function save(array $forms, bool $allowPartialSave = true): bool
543
    {
544
        $result = true;
545
        $values = [];
546
        $toSave = [];
547
        $isSetupScript = Config::getInstance()->isSetup();
0 ignored issues
show
Deprecated Code introduced by
The function PhpMyAdmin\Config::getInstance() has been deprecated: Use dependency injection instead. ( Ignorable by Annotation )

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

547
        $isSetupScript = /** @scrutinizer ignore-deprecated */ Config::getInstance()->isSetup();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
548
        if ($isSetupScript) {
549
            $this->loadUserprefsInfo();
550
        }
551
552
        $this->errors = [];
553
        foreach ($forms as $formName) {
554
            if (! isset($this->forms[$formName])) {
555
                continue;
556
            }
557
558
            $form = $this->forms[$formName];
559
            // get current server id
560
            $changeIndex = $form->index === 0
561
                ? $this->configFile->getServerCount() + 1
562
                : false;
563
            // grab POST values
564
            foreach ($form->fields as $field => $systemPath) {
565
                $workPath = array_search($systemPath, $this->systemPaths);
566
                $key = $this->translatedPaths[$workPath];
567
                $type = $form->getOptionType($field);
568
569
                // skip groups
570
                if ($type === 'group') {
571
                    continue;
572
                }
573
574
                // ensure the value is set
575
                if (! isset($_POST[$key])) {
576
                    // checkboxes aren't set by browsers if they're off
577
                    if ($type !== 'boolean') {
578
                        $this->errors[$form->name][] = sprintf(
579
                            __('Missing data for %s'),
580
                            '<i>' . Descriptions::get($systemPath) . '</i>',
581
                        );
582
                        $result = false;
583
                        continue;
584
                    }
585
586
                    $_POST[$key] = false;
587
                }
588
589
                // user preferences allow/disallow
590
                if ($isSetupScript && isset($this->userprefsKeys[$systemPath])) {
591
                    if (isset($this->userprefsDisallow[$systemPath], $_POST[$key . '-userprefs-allow'])) {
592
                        unset($this->userprefsDisallow[$systemPath]);
593
                    } elseif (! isset($_POST[$key . '-userprefs-allow'])) {
594
                        $this->userprefsDisallow[$systemPath] = true;
595
                    }
596
                }
597
598
                // cast variables to correct type
599
                switch ($type) {
600
                    case 'double':
601
                        $_POST[$key] = Util::requestString($_POST[$key]);
602
                        $_POST[$key] = (float) $_POST[$key];
603
                        break;
604
                    case 'boolean':
605
                    case 'integer':
606
                        if ($_POST[$key] !== '') {
607
                            $_POST[$key] = Util::requestString($_POST[$key]);
608
                            // phpcs:ignore Generic.PHP.ForbiddenFunctions
609
                            settype($_POST[$key], $type);
610
                        }
611
612
                        break;
613
                    case 'select':
614
                        $successfullyValidated = $this->validateSelect(
615
                            $_POST[$key],
616
                            $form->getOptionValueList($systemPath),
617
                        );
618
                        if (! $successfullyValidated) {
619
                            $this->errors[$workPath][] = __('Incorrect value!');
620
                            $result = false;
621
                            // "continue" for the $form->fields foreach-loop
622
                            continue 2;
623
                        }
624
625
                        break;
626
                    case 'string':
627
                    case 'short_string':
628
                        $_POST[$key] = Util::requestString($_POST[$key]);
629
                        break;
630
                    case 'array':
631
                        // eliminate empty values and ensure we have an array
632
                        $postValues = is_array($_POST[$key])
633
                        ? $_POST[$key]
634
                        : explode("\n", $_POST[$key]);
635
                        $_POST[$key] = [];
636
                        $this->fillPostArrayParameters($postValues, $key);
637
                        break;
638
                }
639
640
                // now we have value with proper type
641
                $values[$systemPath] = $_POST[$key];
642
                if ($changeIndex !== false) {
643
                    $workPath = str_replace(
644
                        'Servers/' . $form->index . '/',
645
                        'Servers/' . $changeIndex . '/',
646
                        $workPath,
647
                    );
648
                }
649
650
                $toSave[$workPath] = $systemPath;
651
            }
652
        }
653
654
        // save forms
655
        if (! $allowPartialSave && $this->errors !== []) {
656
            // don't look for non-critical errors
657
            $this->validate();
658
659
            return $result;
660
        }
661
662
        foreach ($toSave as $workPath => $path) {
663
            // TrustedProxies requires changes before saving
664
            if ($path === 'TrustedProxies') {
665
                $proxies = [];
666
                $i = 0;
667
                foreach ($values[$path] as $value) {
668
                    $matches = [];
669
                    if (preg_match('/^(.+):(?:[ ]?)(\\w+)$/', $value, $matches) === 1) {
670
                        // correct 'IP: HTTP header' pair
671
                        $ip = trim($matches[1]);
672
                        $proxies[$ip] = trim($matches[2]);
673
                    } else {
674
                        // save also incorrect values
675
                        $proxies['-' . $i] = $value;
676
                        $i++;
677
                    }
678
                }
679
680
                $values[$path] = $proxies;
681
            }
682
683
            $this->configFile->set($workPath, $values[$path], $path);
684
        }
685
686
        if ($isSetupScript) {
687
            $this->configFile->set(
688
                'UserprefsDisallow',
689
                array_keys($this->userprefsDisallow),
690
            );
691
        }
692
693
        // don't look for non-critical errors
694
        $this->validate();
695
696
        return $result;
697
    }
698
699
    /**
700
     * Tells whether form validation failed
701
     */
702 4
    public function hasErrors(): bool
703
    {
704 4
        return $this->errors !== [];
705
    }
706
707
    /**
708
     * Returns link to documentation
709
     *
710
     * @param string $path Path to documentation
711
     */
712 4
    public function getDocLink(string $path): string
713
    {
714 4
        if (str_starts_with($path, 'Import') || str_starts_with($path, 'Export')) {
715 4
            return '';
716
        }
717
718 4
        return MySQLDocumentation::getDocumentationLink(
719 4
            'config',
720 4
            'cfg_' . $this->getOptName($path),
721 4
            $this->isSetupScript ? '../' : './',
722 4
        );
723
    }
724
725
    /**
726
     * Changes path so it can be used in URLs
727
     *
728
     * @param string $path Path
729
     */
730 8
    private function getOptName(string $path): string
731
    {
732 8
        return str_replace(['Servers/1/', '/'], ['Servers/', '_'], $path);
733
    }
734
735
    /**
736
     * Fills out {@link userprefs_keys} and {@link userprefs_disallow}
737
     */
738 4
    private function loadUserprefsInfo(): void
739
    {
740 4
        if ($this->userprefsKeys !== null) {
741
            return;
742
        }
743
744 4
        $this->userprefsKeys = array_flip(UserFormList::getFields());
745
        // read real config for user preferences display
746 4
        $config = Config::getInstance();
0 ignored issues
show
Deprecated Code introduced by
The function PhpMyAdmin\Config::getInstance() has been deprecated: Use dependency injection instead. ( Ignorable by Annotation )

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

746
        $config = /** @scrutinizer ignore-deprecated */ Config::getInstance();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
747 4
        $userPrefsDisallow = $config->isSetup()
748
            ? $this->configFile->get('UserprefsDisallow', [])
749 4
            : $config->settings['UserprefsDisallow'];
750 4
        $this->userprefsDisallow = array_flip($userPrefsDisallow ?? []);
751
    }
752
753
    /**
754
     * Sets field comments and warnings based on current environment
755
     *
756
     * @param string  $systemPath Path to settings
757
     * @param mixed[] $opts       Chosen options
758
     */
759 4
    private function setComments(string $systemPath, array &$opts): void
760
    {
761
        // RecodingEngine - mark unavailable types
762 4
        if ($systemPath === 'RecodingEngine') {
763 4
            $comment = '';
764 4
            if (! function_exists('iconv')) {
765
                $opts['values']['iconv'] .= ' (' . __('unavailable') . ')';
766
                $comment = sprintf(
767
                    __('"%s" requires %s extension'),
768
                    'iconv',
769
                    'iconv',
770
                );
771
            }
772
773
            /* mbstring is always there thanks to polyfill */
774 4
            $opts['comment'] = $comment;
775 4
            $opts['comment_warning'] = true;
776
        }
777
778
        // ZipDump, GZipDump, BZipDump - check function availability
779 4
        if ($systemPath === 'ZipDump' || $systemPath === 'GZipDump' || $systemPath === 'BZipDump') {
780 4
            $comment = '';
781 4
            $funcs = [
782 4
                'ZipDump' => ['zip_open', 'gzcompress'],
783 4
                'GZipDump' => ['gzopen', 'gzencode'],
784 4
                'BZipDump' => ['bzopen', 'bzcompress'],
785 4
            ];
786 4
            if (! function_exists($funcs[$systemPath][0])) {
787
                $comment = sprintf(
788
                    __(
789
                        'Compressed import will not work due to missing function %s.',
790
                    ),
791
                    $funcs[$systemPath][0],
792
                );
793
            }
794
795 4
            if (! function_exists($funcs[$systemPath][1])) {
796
                $comment .= ($comment !== '' ? '; ' : '') . sprintf(
797
                    __(
798
                        'Compressed export will not work due to missing function %s.',
799
                    ),
800
                    $funcs[$systemPath][1],
801
                );
802
            }
803
804 4
            $opts['comment'] = $comment;
805 4
            $opts['comment_warning'] = true;
806
        }
807
808 4
        $config = Config::getInstance();
0 ignored issues
show
Deprecated Code introduced by
The function PhpMyAdmin\Config::getInstance() has been deprecated: Use dependency injection instead. ( Ignorable by Annotation )

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

808
        $config = /** @scrutinizer ignore-deprecated */ Config::getInstance();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
809 4
        if ($config->isSetup()) {
810
            return;
811
        }
812
813 4
        if ($systemPath !== 'MaxDbList' && $systemPath !== 'MaxTableList' && $systemPath !== 'QueryHistoryMax') {
814 4
            return;
815
        }
816
817 4
        $opts['comment'] = sprintf(
818 4
            __('maximum %s'),
819 4
            $config->settings[$systemPath],
820 4
        );
821
    }
822
823
    /**
824
     * Copy items of an array to $_POST variable
825
     *
826
     * @param mixed[] $postValues List of parameters
827
     * @param string  $key        Array key
828
     */
829
    private function fillPostArrayParameters(array $postValues, string $key): void
830
    {
831
        foreach ($postValues as $v) {
832
            $v = Util::requestString($v);
833
            if ($v === '') {
834
                continue;
835
            }
836
837
            $_POST[$key][] = $v;
838
        }
839
    }
840
}
841