Test Failed
Branch develop (db5506)
by Felipe
03:46
created

FulltextController::doSaveCreateConfig()   C

Complexity

Conditions 8
Paths 36

Size

Total Lines 39
Code Lines 25

Duplication

Lines 5
Ratio 12.82 %

Importance

Changes 0
Metric Value
cc 8
eloc 25
nc 36
nop 0
dl 5
loc 39
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
namespace PHPPgAdmin\Controller;
4
5
use \PHPPgAdmin\Decorators\Decorator;
6
7
/**
8
 * Base controller class
9
 */
10
class FulltextController extends BaseController
11
{
12
    public $_name = 'FulltextController';
13
14
    public function render()
0 ignored issues
show
Coding Style introduced by
render uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
render uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
15
    {
16
        $conf = $this->conf;
1 ignored issue
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
17
        $misc = $this->misc;
0 ignored issues
show
Unused Code introduced by
The assignment to $misc is dead and can be removed.
Loading history...
18
        $lang = $this->lang;
19
20
        $action = $this->action;
21
        if ($action == 'tree') {
22
            return $this->doTree();
23
        } elseif ($action == 'subtree') {
24
            return $this->doSubTree($_REQUEST['what']);
25
        }
26
27
        $this->printHeader($lang['strschemas']);
28
        $this->printBody();
29
30
        if (isset($_POST['cancel'])) {
31
            if (isset($_POST['prev_action'])) {
32
                $action = $_POST['prev_action'];
33
            } else {
34
                $action = '';
35
            }
36
        }
37
38
        switch ($action) {
39
            case 'createconfig':
40
                if (isset($_POST['create'])) {
41
                    $this->doSaveCreateConfig();
42
                } else {
43
                    $this->doCreateConfig();
44
                }
45
46
                break;
47
            case 'alterconfig':
48
                if (isset($_POST['alter'])) {
49
                    $this->doSaveAlterConfig();
50
                } else {
51
                    $this->doAlterConfig();
52
                }
53
54
                break;
55
            case 'dropconfig':
56
                if (isset($_POST['drop'])) {
57
                    $this->doDropConfig(false);
58
                } else {
59
                    $this->doDropConfig(true);
60
                }
61
62
                break;
63
            case 'viewconfig':
64
                $this->doViewConfig($_REQUEST['ftscfg']);
65
                break;
66
            case 'viewparsers':
67
                $this->doViewParsers();
68
                break;
69
            case 'viewdicts':
70
                $this->doViewDicts();
71
                break;
72
            case 'createdict':
73
                if (isset($_POST['create'])) {
74
                    $this->doSaveCreateDict();
75
                } else {
76
                    doCreateDict();
0 ignored issues
show
Bug introduced by
The function doCreateDict 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

76
                    /** @scrutinizer ignore-call */ doCreateDict();
Loading history...
77
                }
78
79
                break;
80
            case 'alterdict':
81
                if (isset($_POST['alter'])) {
82
                    $this->doSaveAlterDict();
83
                } else {
84
                    $this->doAlterDict();
85
                }
86
87
                break;
88
            case 'dropdict':
89
                if (isset($_POST['drop'])) {
90
                    $this->doDropDict(false);
91
                } else {
92
                    $this->doDropDict(true);
93
                }
94
95
                break;
96
            case 'dropmapping':
97
                if (isset($_POST['drop'])) {
98
                    $this->doDropMapping(false);
99
                } else {
100
                    $this->doDropMapping(true);
101
                }
102
103
                break;
104
            case 'altermapping':
105
                if (isset($_POST['alter'])) {
106
                    $this->doSaveAlterMapping();
107
                } else {
108
                    $this->doAlterMapping();
109
                }
110
111
                break;
112
            case 'addmapping':
113
                if (isset($_POST['add'])) {
114
                    $this->doSaveAddMapping();
115
                } else {
116
                    $this->doAddMapping();
117
                }
118
119
                break;
120
121
            default:
122
                $this->doDefault();
123
                break;
124
        }
125
126
        return $this->printFooter();
127
    }
128
129
    public function doDefault($msg = '')
0 ignored issues
show
Coding Style introduced by
doDefault uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
130
    {
131
        $conf = $this->conf;
132
        $misc = $this->misc;
133
        $lang = $this->lang;
134
        $data = $misc->getDatabaseAccessor();
135
136
        $this->printTrail('schema');
137
        $this->printTabs('schema', 'fulltext');
138
        $this->printTabs('fulltext', 'ftsconfigs');
139
        $this->printMsg($msg);
140
141
        $cfgs = $data->getFtsConfigurations(false);
142
143
        $columns = [
144
            'configuration' => [
145
                'title' => $lang['strftsconfig'],
146
                'field' => Decorator::field('name'),
147
                'url'   => "fulltext.php?action=viewconfig&amp;{$misc->href}&amp;",
148
                'vars'  => ['ftscfg' => 'name'],
149
            ],
150
            'schema'        => [
151
                'title' => $lang['strschema'],
152
                'field' => Decorator::field('schema'),
153
            ],
154
            'actions'       => [
155
                'title' => $lang['stractions'],
156
            ],
157
            'comment'       => [
158
                'title' => $lang['strcomment'],
159
                'field' => Decorator::field('comment'),
160
            ],
161
        ];
162
163
        $actions = [
164
            'drop'  => [
165
                'content' => $lang['strdrop'],
166
                'attr'    => [
167
                    'href' => [
168
                        'url'     => 'fulltext.php',
169
                        'urlvars' => [
170
                            'action' => 'dropconfig',
171
                            'ftscfg' => Decorator::field('name'),
172
                        ],
173
                    ],
174
                ],
175
            ],
176
            'alter' => [
177
                'content' => $lang['stralter'],
178
                'attr'    => [
179
                    'href' => [
180
                        'url'     => 'fulltext.php',
181
                        'urlvars' => [
182
                            'action' => 'alterconfig',
183
                            'ftscfg' => Decorator::field('name'),
184
                        ],
185
                    ],
186
                ],
187
            ],
188
        ];
189
190
        echo $this->printTable($cfgs, $columns, $actions, 'fulltext-fulltext', $lang['strftsnoconfigs']);
191
192
        $navlinks = [
193
            'createconf' => [
194
                'attr'    => [
195
                    'href' => [
196
                        'url'     => 'fulltext.php',
197
                        'urlvars' => [
198
                            'action'   => 'createconfig',
199
                            'server'   => $_REQUEST['server'],
200
                            'database' => $_REQUEST['database'],
201
                            'schema'   => $_REQUEST['schema'],
202
                        ],
203
                    ],
204
                ],
205
                'content' => $lang['strftscreateconfig'],
206
            ],
207
        ];
208
209
        $this->printNavLinks($navlinks, 'fulltext-fulltext', get_defined_vars());
210
    }
211
212
    /**
213
     * Generate XML for the browser tree.
214
     */
215 View Code Duplication
    public function doTree()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
    {
217
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
218
        $misc = $this->misc;
219
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
220
        $data = $misc->getDatabaseAccessor();
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
221
222
        $tabs  = $misc->getNavTabs('fulltext');
223
        $items = $this->adjustTabsForTree($tabs);
224
225
        $reqvars = $misc->getRequestVars('ftscfg');
226
227
        $attrs = [
228
            'text'   => Decorator::field('title'),
229
            'icon'   => Decorator::field('icon'),
230
            'action' => Decorator::actionurl('fulltext.php',
231
                $reqvars,
232
                field('urlvars')
0 ignored issues
show
Bug introduced by
The function field 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

232
                /** @scrutinizer ignore-call */ field('urlvars')
Loading history...
233
            ),
234
            'branch' => Decorator::url('fulltext.php',
235
                $reqvars,
236
                [
237
                    'action' => 'subtree',
238
                    'what'   => Decorator::field('icon'), // IZ: yeah, it's ugly, but I do not want to change navigation tabs arrays
239
                ]
240
            ),
241
        ];
242
243
        return $this->printTree($items, $attrs, 'fts');
244
    }
245
246
    public function doSubTree($what)
247
    {
248
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
249
        $misc = $this->misc;
250
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
251
        $data = $misc->getDatabaseAccessor();
252
253
        switch ($what) {
254
            case 'FtsCfg':
255
                $items   = $data->getFtsConfigurations(false);
256
                $urlvars = ['action' => 'viewconfig', 'ftscfg' => Decorator::field('name')];
257
                break;
258
            case 'FtsDict':
259
                $items   = $data->getFtsDictionaries(false);
260
                $urlvars = ['action' => 'viewdicts'];
261
                break;
262
            case 'FtsParser':
263
                $items   = $data->getFtsParsers(false);
264
                $urlvars = ['action' => 'viewparsers'];
265
                break;
266
            default:
267
                return;
268
        }
269
270
        $reqvars = $misc->getRequestVars('ftscfg');
271
272
        $attrs = [
273
            'text'    => Decorator::field('name'),
274
            'icon'    => $what,
275
            'toolTip' => Decorator::field('comment'),
276
            'action'  => Decorator::actionurl('fulltext.php',
277
                $reqvars,
278
                $urlvars
279
            ),
280
            'branch'  => Decorator::ifempty(Decorator::field('branch'),
281
                '',
282
                url('fulltext.php',
0 ignored issues
show
Bug introduced by
The function url 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

282
                /** @scrutinizer ignore-call */ url('fulltext.php',
Loading history...
283
                    $reqvars,
284
                    [
285
                        'action' => 'subtree',
286
                        'ftscfg' => Decorator::field('name'),
287
                    ]
288
                )
289
            ),
290
        ];
291
292
        return $this->printTree($items, $attrs, strtolower($what));
293
    }
294
295 View Code Duplication
    public function doDropConfig($confirm)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
doDropConfig uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doDropConfig uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
296
    {
297
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
298
        $misc = $this->misc;
299
        $lang = $this->lang;
300
        $data = $misc->getDatabaseAccessor();
301
302
        if ($confirm) {
303
            $this->printTrail('ftscfg');
304
            $this->printTitle($lang['strdrop'], 'pg.ftscfg.drop');
305
306
            echo '<p>', sprintf($lang['strconfdropftsconfig'], $misc->printVal($_REQUEST['ftscfg'])), "</p>\n";
307
308
            echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
309
            echo "<p><input type=\"checkbox\" id=\"cascade\" name=\"cascade\" /> <label for=\"cascade\">{$lang['strcascade']}</label></p>\n";
310
            echo "<p><input type=\"hidden\" name=\"action\" value=\"dropconfig\" />\n";
311
            echo '<input type="hidden" name="database" value="', htmlspecialchars($_REQUEST['database']), "\" />\n";
312
            echo '<input type="hidden" name="ftscfg" value="', htmlspecialchars($_REQUEST['ftscfg']), "\" />\n";
313
            echo $misc->form;
314
            echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n";
315
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
316
            echo "</form>\n";
317
        } else {
318
            $status = $data->dropFtsConfiguration($_POST['ftscfg'], isset($_POST['cascade']));
319
            if ($status == 0) {
320
                $this->misc->setReloadBrowser(true);
321
                $this->doDefault($lang['strftsconfigdropped']);
322
            } else {
323
                $this->doDefault($lang['strftsconfigdroppedbad']);
324
            }
325
        }
326
    }
327
328
    public function doDropDict($confirm)
0 ignored issues
show
Coding Style introduced by
doDropDict uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doDropDict uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
329
    {
330
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
331
        $misc = $this->misc;
332
        $lang = $this->lang;
333
        $data = $misc->getDatabaseAccessor();
334
335
        if ($confirm) {
336
            $this->printTrail('ftscfg'); // TODO: change to smth related to dictionary
337
            $this->printTitle($lang['strdrop'], 'pg.ftsdict.drop');
338
339
            echo '<p>', sprintf($lang['strconfdropftsdict'], $misc->printVal($_REQUEST['ftsdict'])), "</p>\n";
340
341
            echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
342
            echo "<p><input type=\"checkbox\" id=\"cascade\" name=\"cascade\" /> <label for=\"cascade\">{$lang['strcascade']}</label></p>\n";
343
            echo "<p><input type=\"hidden\" name=\"action\" value=\"dropdict\" />\n";
344
            echo '<input type="hidden" name="database" value="', htmlspecialchars($_REQUEST['database']), "\" />\n";
345
            echo '<input type="hidden" name="ftsdict" value="', htmlspecialchars($_REQUEST['ftsdict']), "\" />\n";
346
            //echo "<input type=\"hidden\" name=\"ftscfg\" value=\"", htmlspecialchars($_REQUEST['ftscfg']), "\" />\n";
347
            echo "<input type=\"hidden\" name=\"prev_action\" value=\"viewdicts\" /></p>\n";
348
            echo $misc->form;
349
            echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n";
350
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
351
            echo "</form>\n";
352
        } else {
353
            $status = $data->dropFtsDictionary($_POST['ftsdict'], isset($_POST['cascade']));
354
            if ($status == 0) {
355
                $this->misc->setReloadBrowser(true);
356
                $this->doViewDicts($lang['strftsdictdropped']);
357
            } else {
358
                $this->doViewDicts($lang['strftsdictdroppedbad']);
359
            }
360
        }
361
    }
362
363
    /**
364
     * Displays a screen where one can enter a new FTS configuration
365
     */
366
    public function doCreateConfig($msg = '')
0 ignored issues
show
Coding Style introduced by
doCreateConfig uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doCreateConfig uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
367
    {
368
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
369
        $misc = $this->misc;
370
        $lang = $this->lang;
371
        $data = $misc->getDatabaseAccessor();
372
373
        $server_info = $misc->getServerInfo();
0 ignored issues
show
Unused Code introduced by
The assignment to $server_info is dead and can be removed.
Loading history...
374
375
        if (!isset($_POST['formName'])) {
376
            $_POST['formName'] = '';
377
        }
378
379
        if (!isset($_POST['formParser'])) {
380
            $_POST['formParser'] = '';
381
        }
382
383
        if (!isset($_POST['formTemplate'])) {
384
            $_POST['formTemplate'] = '';
385
        }
386
387
        if (!isset($_POST['formWithMap'])) {
388
            $_POST['formWithMap'] = '';
389
        }
390
391
        if (!isset($_POST['formComment'])) {
392
            $_POST['formComment'] = '';
393
        }
394
395
        // Fetch all FTS configurations from the database
396
        $ftscfgs = $data->getFtsConfigurations();
397
        // Fetch all FTS parsers from the database
398
        $ftsparsers = $data->getFtsParsers();
399
400
        $this->printTrail('schema');
401
        $this->printTitle($lang['strftscreateconfig'], 'pg.ftscfg.create');
402
        $this->printMsg($msg);
403
404
        echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
405
        echo "<table>\n";
406
        /* conf name */
407
        echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n";
408
        echo "\t\t<td class=\"data1\"><input name=\"formName\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
409
        htmlspecialchars($_POST['formName']), "\" /></td>\n\t</tr>\n";
410
411
        // Template
412
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strftstemplate']}</th>\n";
413
        echo "\t\t<td class=\"data1\">";
414
415
        $tpls   = [];
416
        $tplsel = '';
417 View Code Duplication
        while (!$ftscfgs->EOF) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
418
            $data->fieldClean($ftscfgs->fields['schema']);
419
            $data->fieldClean($ftscfgs->fields['name']);
420
            $tplname        = $ftscfgs->fields['schema'] . '.' . $ftscfgs->fields['name'];
421
            $tpls[$tplname] = serialize([
422
                'name'   => $ftscfgs->fields['name'],
423
                'schema' => $ftscfgs->fields['schema'],
424
            ]);
425
            if ($_POST['formTemplate'] == $tpls[$tplname]) {
426
                $tplsel = htmlspecialchars($tpls[$tplname]);
427
            }
428
            $ftscfgs->moveNext();
429
        }
430
        echo \PHPPgAdmin\XHtml\HTMLController::printCombo($tpls, 'formTemplate', true, $tplsel, false);
431
        echo "\n\t\t</td>\n\t</tr>\n";
432
433
        // Parser
434
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strftsparser']}</th>\n";
435
        echo "\t\t<td class=\"data1\">\n";
436
        $ftsparsers_ = [];
437
        $ftsparsel   = '';
438 View Code Duplication
        while (!$ftsparsers->EOF) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
439
            $data->fieldClean($ftsparsers->fields['schema']);
440
            $data->fieldClean($ftsparsers->fields['name']);
441
            $parsername = $ftsparsers->fields['schema'] . '.' . $ftsparsers->fields['name'];
442
443
            $ftsparsers_[$parsername] = serialize([
444
                'parser' => $ftsparsers->fields['name'],
445
                'schema' => $ftsparsers->fields['schema'],
446
            ]);
447
            if ($_POST['formParser'] == $ftsparsers_[$parsername]) {
448
                $ftsparsel = htmlspecialchars($ftsparsers_[$parsername]);
449
            }
450
            $ftsparsers->moveNext();
451
        }
452
        echo \PHPPgAdmin\XHtml\HTMLController::printCombo($ftsparsers_, 'formParser', true, $ftsparsel, false);
453
        echo "\n\t\t</td>\n\t</tr>\n";
454
455
        // Comment
456
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strcomment']}</th>\n";
457
        echo "\t\t<td class=\"data1\"><textarea name=\"formComment\" rows=\"3\" cols=\"32\">",
458
        htmlspecialchars($_POST['formComment']), "</textarea></td>\n\t</tr>\n";
459
460
        echo "</table>\n";
461
        echo "<p>\n";
462
        echo "<input type=\"hidden\" name=\"action\" value=\"createconfig\" />\n";
463
        echo '<input type="hidden" name="database" value="', htmlspecialchars($_REQUEST['database']), "\" />\n";
464
        echo $misc->form;
465
        echo "<input type=\"submit\" name=\"create\" value=\"{$lang['strcreate']}\" />\n";
466
        echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />\n";
467
        echo "</p>\n";
468
        echo "</form>\n";
469
    }
470
471
    /**
472
     * Actually creates the new FTS configuration in the database
473
     */
474
    public function doSaveCreateConfig()
0 ignored issues
show
Coding Style introduced by
doSaveCreateConfig uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
475
    {
476
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
477
        $misc = $this->misc;
478
        $lang = $this->lang;
479
        $data = $misc->getDatabaseAccessor();
480
481
        $err = '';
482
        // Check that they've given a name
483
        if ($_POST['formName'] == '') {
484
            $err .= "{$lang['strftsconfigneedsname']}<br />";
485
        }
486
487
        if (($_POST['formParser'] != '') && ($_POST['formTemplate'] != '')) {
488
            $err .= "{$lang['strftscantparsercopy']}<br />";
489
        }
490
491
        if ($err != '') {
492
            return doCreateConfig($err);
0 ignored issues
show
Bug introduced by
The function doCreateConfig 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

492
            return /** @scrutinizer ignore-call */ doCreateConfig($err);
Loading history...
493
        }
494
495
        if ($_POST['formParser'] != '') {
496
            $formParser = unserialize($_POST['formParser']);
497
        } else {
498
            $formParser = '';
499
        }
500
501 View Code Duplication
        if ($_POST['formTemplate'] != '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
502
            $formTemplate = unserialize($_POST['formTemplate']);
503
        } else {
504
            $formTemplate = '';
505
        }
506
507
        $status = $data->createFtsConfiguration($_POST['formName'], $formParser, $formTemplate, $_POST['formComment']);
508
        if ($status == 0) {
509
            $this->misc->setReloadBrowser(true);
510
            $this->doDefault($lang['strftsconfigcreated']);
511
        } else {
512
            $this->doCreateConfig($lang['strftsconfigcreatedbad']);
513
        }
514
    }
515
516
    /**
517
     * Display a form to permit editing FTS configuration properies.
518
     */
519
    public function doAlterConfig($msg = '')
0 ignored issues
show
Coding Style introduced by
doAlterConfig uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doAlterConfig uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
520
    {
521
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
522
        $misc = $this->misc;
523
        $lang = $this->lang;
524
        $data = $misc->getDatabaseAccessor();
525
526
        $this->printTrail('ftscfg');
527
        $this->printTitle($lang['stralter'], 'pg.ftscfg.alter');
528
        $this->printMsg($msg);
529
530
        $ftscfg = $data->getFtsConfigurationByName($_REQUEST['ftscfg']);
531
        if ($ftscfg->recordCount() > 0) {
532
            if (!isset($_POST['formComment'])) {
533
                $_POST['formComment'] = $ftscfg->fields['comment'];
534
            }
535
536
            if (!isset($_POST['ftscfg'])) {
537
                $_POST['ftscfg'] = $_REQUEST['ftscfg'];
538
            }
539
540
            if (!isset($_POST['formName'])) {
541
                $_POST['formName'] = $_REQUEST['ftscfg'];
542
            }
543
544
            if (!isset($_POST['formParser'])) {
545
                $_POST['formParser'] = '';
546
            }
547
548
            // Fetch all FTS parsers from the database
549
            $ftsparsers = $data->getFtsParsers();
1 ignored issue
show
Unused Code introduced by
The assignment to $ftsparsers is dead and can be removed.
Loading history...
550
551
            echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
552
            echo "<table>\n";
553
554
            echo "\t<tr>\n";
555
            echo "\t\t<th class=\"data left required\">{$lang['strname']}</th>\n";
556
            echo "\t\t<td class=\"data1\">";
557
            echo "\t\t\t<input name=\"formName\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
558
            htmlspecialchars($_POST['formName']), "\" />\n";
559
            echo "\t\t</td>\n";
560
            echo "\t</tr>\n";
561
562
            // Comment
563
            echo "\t<tr>\n";
564
            echo "\t\t<th class=\"data\">{$lang['strcomment']}</th>\n";
565
            echo "\t\t<td class=\"data1\"><textarea cols=\"32\" rows=\"3\"name=\"formComment\">", htmlspecialchars($_POST['formComment']), "</textarea></td>\n";
566
            echo "\t</tr>\n";
567
            echo "</table>\n";
568
            echo "<p><input type=\"hidden\" name=\"action\" value=\"alterconfig\" />\n";
569
            echo '<input type="hidden" name="ftscfg" value="', htmlspecialchars($_POST['ftscfg']), "\" />\n";
570
            echo $misc->form;
571
            echo "<input type=\"submit\" name=\"alter\" value=\"{$lang['stralter']}\" />\n";
572
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
573
            echo "</form>\n";
574
        } else {
575
            echo "<p>{$lang['strnodata']}</p>\n";
576
        }
577
    }
578
579
    /**
580
     * Save the form submission containing changes to a FTS configuration
581
     */
582
    public function doSaveAlterConfig()
0 ignored issues
show
Coding Style introduced by
doSaveAlterConfig uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
583
    {
584
        $conf   = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
585
        $misc   = $this->misc;
586
        $lang   = $this->lang;
587
        $data   = $misc->getDatabaseAccessor();
588
        $status = $data->updateFtsConfiguration($_POST['ftscfg'], $_POST['formComment'], $_POST['formName']);
589
        if ($status == 0) {
590
            $this->doDefault($lang['strftsconfigaltered']);
591
        } else {
592
            $this->doAlterConfig($lang['strftsconfigalteredbad']);
593
        }
594
    }
595
596
    /**
597
     * View list of FTS parsers
598
     */
599 View Code Duplication
    public function doViewParsers($msg = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
600
    {
601
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
602
        $misc = $this->misc;
603
        $lang = $this->lang;
604
        $data = $misc->getDatabaseAccessor();
605
606
        $this->printTrail('schema');
607
        $this->printTabs('schema', 'fulltext');
608
        $this->printTabs('fulltext', 'ftsparsers');
609
        $this->printMsg($msg);
610
611
        $parsers = $data->getFtsParsers(false);
612
613
        $columns = [
614
            'schema'  => [
615
                'title' => $lang['strschema'],
616
                'field' => Decorator::field('schema'),
617
            ],
618
            'name'    => [
619
                'title' => $lang['strname'],
620
                'field' => Decorator::field('name'),
621
            ],
622
            'comment' => [
623
                'title' => $lang['strcomment'],
624
                'field' => Decorator::field('comment'),
625
            ],
626
        ];
627
628
        $actions = [];
629
630
        echo $this->printTable($parsers, $columns, $actions, 'fulltext-viewparsers', $lang['strftsnoparsers']);
631
632
        //TODO: navlink to "create parser"
633
    }
634
635
    /**
636
     * View list of FTS dictionaries
637
     */
638
    public function doViewDicts($msg = '')
0 ignored issues
show
Coding Style introduced by
doViewDicts uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
639
    {
640
        $conf = $this->conf;
641
        $misc = $this->misc;
642
        $lang = $this->lang;
643
        $data = $misc->getDatabaseAccessor();
644
645
        $this->printTrail('schema');
646
        $this->printTabs('schema', 'fulltext');
647
        $this->printTabs('fulltext', 'ftsdicts');
648
        $this->printMsg($msg);
649
650
        $dicts = $data->getFtsDictionaries(false);
651
652
        $columns = [
653
            'schema'  => [
654
                'title' => $lang['strschema'],
655
                'field' => Decorator::field('schema'),
656
            ],
657
            'name'    => [
658
                'title' => $lang['strname'],
659
                'field' => Decorator::field('name'),
660
            ],
661
            'actions' => [
662
                'title' => $lang['stractions'],
663
            ],
664
            'comment' => [
665
                'title' => $lang['strcomment'],
666
                'field' => Decorator::field('comment'),
667
            ],
668
        ];
669
670
        $actions = [
671
            'drop'  => [
672
                'content' => $lang['strdrop'],
673
                'attr'    => [
674
                    'href' => [
675
                        'url'     => 'fulltext.php',
676
                        'urlvars' => [
677
                            'action'  => 'dropdict',
678
                            'ftsdict' => Decorator::field('name'),
679
                        ],
680
                    ],
681
                ],
682
            ],
683
            'alter' => [
684
                'content' => $lang['stralter'],
685
                'attr'    => [
686
                    'href' => [
687
                        'url'     => 'fulltext.php',
688
                        'urlvars' => [
689
                            'action'  => 'alterdict',
690
                            'ftsdict' => Decorator::field('name'),
691
                        ],
692
                    ],
693
                ],
694
            ],
695
        ];
696
697
        echo $this->printTable($dicts, $columns, $actions, 'fulltext-viewdicts', $lang['strftsnodicts']);
698
699
        $navlinks = [
700
            'createdict' => [
701
                'attr'    => [
702
                    'href' => [
703
                        'url'     => 'fulltext.php',
704
                        'urlvars' => [
705
                            'action'   => 'createdict',
706
                            'server'   => $_REQUEST['server'],
707
                            'database' => $_REQUEST['database'],
708
                            'schema'   => $_REQUEST['schema'],
709
                        ],
710
                    ],
711
                ],
712
                'content' => $lang['strftscreatedict'],
713
            ],
714
        ];
715
716
        $this->printNavLinks($navlinks, 'fulltext-viewdicts', get_defined_vars());
717
    }
718
719
    /**
720
     * View details of FTS configuration given
721
     */
722
    public function doViewConfig($ftscfg, $msg = '')
0 ignored issues
show
Coding Style introduced by
doViewConfig uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
723
    {
724
        $conf = $this->conf;
725
        $misc = $this->misc;
726
        $lang = $this->lang;
727
        $data = $misc->getDatabaseAccessor();
728
729
        $this->printTrail('ftscfg');
730
        $this->printTabs('schema', 'fulltext');
731
        $this->printTabs('fulltext', 'ftsconfigs');
732
        $this->printMsg($msg);
733
734
        echo "<h3>{$lang['strftsconfigmap']}</h3>\n";
735
736
        $map = $data->getFtsConfigurationMap($ftscfg);
737
738
        $columns = [
739
            'name'         => [
740
                'title' => $lang['strftsmapping'],
741
                'field' => Decorator::field('name'),
742
            ],
743
            'dictionaries' => [
744
                'title' => $lang['strftsdicts'],
745
                'field' => Decorator::field('dictionaries'),
746
            ],
747
            'actions'      => [
748
                'title' => $lang['stractions'],
749
            ],
750
            'comment'      => [
751
                'title' => $lang['strcomment'],
752
                'field' => Decorator::field('description'),
753
            ],
754
        ];
755
756
        $actions = [
757
            'drop'         => [
758
                'multiaction' => 'dropmapping',
759
                'content'     => $lang['strdrop'],
760
                'attr'        => [
761
                    'href' => [
762
                        'url'     => 'fulltext.php',
763
                        'urlvars' => [
764
                            'action'  => 'dropmapping',
765
                            'mapping' => Decorator::field('name'),
766
                            'ftscfg'  => Decorator::field('cfgname'),
767
                        ],
768
                    ],
769
                ],
770
            ],
771
            'alter'        => [
772
                'content' => $lang['stralter'],
773
                'attr'    => [
774
                    'href' => [
775
                        'url'     => 'fulltext.php',
776
                        'urlvars' => [
777
                            'action'  => 'altermapping',
778
                            'mapping' => Decorator::field('name'),
779
                            'ftscfg'  => Decorator::field('cfgname'),
780
                        ],
781
                    ],
782
                ],
783
            ],
784
            'multiactions' => [
785
                'keycols' => ['mapping' => 'name'],
786
                'url'     => 'fulltext.php',
787
                'default' => null,
788
                'vars'    => ['ftscfg' => $ftscfg],
789
            ],
790
791
        ];
792
793
        echo $this->printTable($map, $columns, $actions, 'fulltext-viewconfig', $lang['strftsemptymap']);
794
795
        $navlinks = [
796
            'addmapping' => [
797
                'attr'    => [
798
                    'href' => [
799
                        'url'     => 'fulltext.php',
800
                        'urlvars' => [
801
                            'action'   => 'addmapping',
802
                            'server'   => $_REQUEST['server'],
803
                            'database' => $_REQUEST['database'],
804
                            'schema'   => $_REQUEST['schema'],
805
                            'ftscfg'   => $ftscfg,
806
                        ],
807
                    ],
808
                ],
809
                'content' => $lang['strftsaddmapping'],
810
            ],
811
        ];
812
813
        $this->printNavLinks($navlinks, 'fulltext-viewconfig', get_defined_vars());
814
    }
815
816
    /**
817
     * Displays a screen where one can enter a details of a new FTS dictionary
818
     */
819
    public function doCreateDict($msg = '')
0 ignored issues
show
Coding Style introduced by
doCreateDict uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doCreateDict uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
820
    {
821
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
822
        $misc = $this->misc;
823
        $lang = $this->lang;
824
        $data = $misc->getDatabaseAccessor();
825
826
        $server_info = $misc->getServerInfo();
0 ignored issues
show
Unused Code introduced by
The assignment to $server_info is dead and can be removed.
Loading history...
827
828
        if (!isset($_POST['formName'])) {
829
            $_POST['formName'] = '';
830
        }
831
832
        if (!isset($_POST['formIsTemplate'])) {
833
            $_POST['formIsTemplate'] = false;
834
        }
835
836
        if (!isset($_POST['formTemplate'])) {
837
            $_POST['formTemplate'] = '';
838
        }
839
840
        if (!isset($_POST['formLexize'])) {
841
            $_POST['formLexize'] = '';
842
        }
843
844
        if (!isset($_POST['formInit'])) {
845
            $_POST['formInit'] = '';
846
        }
847
848
        if (!isset($_POST['formOption'])) {
849
            $_POST['formOption'] = '';
850
        }
851
852
        if (!isset($_POST['formComment'])) {
853
            $_POST['formComment'] = '';
854
        }
855
856
        // Fetch all FTS dictionaries from the database
857
        $ftstpls = $data->getFtsDictionaryTemplates();
858
859
        $this->printTrail('schema');
860
        // TODO: create doc links
861
        $this->printTitle($lang['strftscreatedict'], 'pg.ftsdict.create');
862
        $this->printMsg($msg);
863
864
        echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
865
        echo "<table>\n";
866
        echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n";
867
        echo "\t\t<td class=\"data1\"><input name=\"formName\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
868
        htmlspecialchars($_POST['formName']), '" />&nbsp;',
869
        '<input type="checkbox" name="formIsTemplate" id="formIsTemplate"', $_POST['formIsTemplate'] ? ' checked="checked" ' : '', " />\n",
870
            "<label for=\"formIsTemplate\">{$lang['strftscreatedicttemplate']}</label></td>\n\t</tr>\n";
871
872
        // Template
873
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strftstemplate']}</th>\n";
874
        echo "\t\t<td class=\"data1\">";
875
        $tpls   = [];
876
        $tplsel = '';
877 View Code Duplication
        while (!$ftstpls->EOF) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
878
            $data->fieldClean($ftstpls->fields['schema']);
879
            $data->fieldClean($ftstpls->fields['name']);
880
            $tplname        = $ftstpls->fields['schema'] . '.' . $ftstpls->fields['name'];
881
            $tpls[$tplname] = serialize([
882
                'name'   => $ftstpls->fields['name'],
883
                'schema' => $ftstpls->fields['schema'],
884
            ]);
885
            if ($_POST['formTemplate'] == $tpls[$tplname]) {
886
                $tplsel = htmlspecialchars($tpls[$tplname]);
887
            }
888
            $ftstpls->moveNext();
889
        }
890
        echo \PHPPgAdmin\XHtml\HTMLController::printCombo($tpls, 'formTemplate', true, $tplsel, false);
891
        echo "\n\t\t</td>\n\t</tr>\n";
892
893
        // TODO: what about maxlengths?
894
        // Lexize
895
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strftslexize']}</th>\n";
896
        echo "\t\t<td class=\"data1\"><input name=\"formLexize\" size=\"32\" maxlength=\"1000\" value=\"",
897
        htmlspecialchars($_POST['formLexize']), '" ', isset($_POST['formIsTemplate']) ? '' : ' disabled="disabled" ',
898
            "/></td>\n\t</tr>\n";
899
900
        // Init
901
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strftsinit']}</th>\n";
902
        echo "\t\t<td class=\"data1\"><input name=\"formInit\" size=\"32\" maxlength=\"1000\" value=\"",
903
        htmlspecialchars($_POST['formInit']), '"', @$_POST['formIsTemplate'] ? '' : ' disabled="disabled" ',
904
            "/></td>\n\t</tr>\n";
905
906
        // Option
907
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strftsoptionsvalues']}</th>\n";
908
        echo "\t\t<td class=\"data1\"><input name=\"formOption\" size=\"32\" maxlength=\"1000\" value=\"",
909
        htmlspecialchars($_POST['formOption']), "\" /></td>\n\t</tr>\n";
910
911
        // Comment
912
        echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strcomment']}</th>\n";
913
        echo "\t\t<td class=\"data1\"><textarea name=\"formComment\" rows=\"3\" cols=\"32\">",
914
        htmlspecialchars($_POST['formComment']), "</textarea></td>\n\t</tr>\n";
915
916
        echo "</table>\n";
917
        echo "<p>\n";
918
        echo "<input type=\"hidden\" name=\"action\" value=\"createdict\" />\n";
919
        echo '<input type="hidden" name="database" value="', htmlspecialchars($_REQUEST['database']), "\" />\n";
920
        echo $misc->form;
921
        echo "<input type=\"submit\" name=\"create\" value=\"{$lang['strcreate']}\" />\n";
922
        echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />\n";
923
        echo "</p>\n";
924
        echo "</form>\n",
925
            "<script type=\"text/javascript\">
926
				function templateOpts() {
927
					isTpl = document.getElementsByName('formIsTemplate')[0].checked;
928
					$this->document.getElementsByName('formTemplate')[0].disabled = isTpl;
0 ignored issues
show
Bug Best Practice introduced by
The property document does not exist on PHPPgAdmin\Controller\FulltextController. Did you maybe forget to declare it?
Loading history...
929
					$this->document.getElementsByName('formOption')[0].disabled = isTpl;
930
					$this->document.getElementsByName('formLexize')[0].disabled = !isTpl;
931
					$this->document.getElementsByName('formInit')[0].disabled = !isTpl;
932
				}
933
934
				$this->document.getElementsByName('formIsTemplate')[0].onchange = templateOpts;
935
936
				templateOpts();
937
			</script>\n";
938
    }
939
940
    /**
941
     * Actually creates the new FTS dictionary in the database
942
     */
943
    public function doSaveCreateDict()
0 ignored issues
show
Coding Style introduced by
doSaveCreateDict uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
944
    {
945
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
946
        $misc = $this->misc;
947
        $lang = $this->lang;
948
        $data = $misc->getDatabaseAccessor();
949
950
        // Check that they've given a name
951
        if ($_POST['formName'] == '') {
952
            $this->doCreateDict($lang['strftsdictneedsname']);
953
        } else {
954
            if (!isset($_POST['formIsTemplate'])) {
955
                $_POST['formIsTemplate'] = false;
956
            }
957
958 View Code Duplication
            if (isset($_POST['formTemplate'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
959
                $formTemplate = unserialize($_POST['formTemplate']);
0 ignored issues
show
Security introduced by
$_POST['formTemplate'] can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST
    in src/controllers/FulltextController.php on line 959

Preventing Object Injection Attacks

If you pass raw user-data to unserialize() for example, this can be used to create an object of any class that is available in your local filesystem. For an attacker, classes that have magic methods like __destruct or __wakeup are particularly interesting in such a case, as they can be exploited very easily.

We recommend to not pass user data to such a function. In case of unserialize, better use JSON to transfer data.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
960
            } else {
961
                $formTemplate = '';
962
            }
963
964
            if (!isset($_POST['formLexize'])) {
965
                $_POST['formLexize'] = '';
966
            }
967
968
            if (!isset($_POST['formInit'])) {
969
                $_POST['formInit'] = '';
970
            }
971
972
            if (!isset($_POST['formOption'])) {
973
                $_POST['formOption'] = '';
974
            }
975
976
            $status = $data->createFtsDictionary($_POST['formName'], $_POST['formIsTemplate'],
977
                $formTemplate, $_POST['formLexize'],
978
                $_POST['formInit'], $_POST['formOption'], $_POST['formComment']
979
            );
980
981
            if ($status == 0) {
982
                $this->misc->setReloadBrowser(true);
983
                $this->doViewDicts($lang['strftsdictcreated']);
984
            } else {
985
                $this->doCreateDict($lang['strftsdictcreatedbad']);
986
            }
987
        }
988
    }
989
990
    /**
991
     * Display a form to permit editing FTS dictionary properies.
992
     */
993
    public function doAlterDict($msg = '')
0 ignored issues
show
Coding Style introduced by
doAlterDict uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doAlterDict uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
994
    {
995
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
996
        $misc = $this->misc;
997
        $lang = $this->lang;
998
        $data = $misc->getDatabaseAccessor();
999
1000
        $this->printTrail('ftscfg'); // TODO: change to smth related to dictionary
1001
        $this->printTitle($lang['stralter'], 'pg.ftsdict.alter');
1002
        $this->printMsg($msg);
1003
1004
        $ftsdict = $data->getFtsDictionaryByName($_REQUEST['ftsdict']);
1005
        if ($ftsdict->recordCount() > 0) {
1006
            if (!isset($_POST['formComment'])) {
1007
                $_POST['formComment'] = $ftsdict->fields['comment'];
1008
            }
1009
1010
            if (!isset($_POST['ftsdict'])) {
1011
                $_POST['ftsdict'] = $_REQUEST['ftsdict'];
1012
            }
1013
1014
            if (!isset($_POST['formName'])) {
1015
                $_POST['formName'] = $_REQUEST['ftsdict'];
1016
            }
1017
1018
            echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
1019
            echo "<table>\n";
1020
1021
            echo "\t<tr>\n";
1022
            echo "\t\t<th class=\"data left required\">{$lang['strname']}</th>\n";
1023
            echo "\t\t<td class=\"data1\">";
1024
            echo "\t\t\t<input name=\"formName\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
1025
            htmlspecialchars($_POST['formName']), "\" />\n";
1026
            echo "\t\t</td>\n";
1027
            echo "\t</tr>\n";
1028
1029
            // Comment
1030
            echo "\t<tr>\n";
1031
            echo "\t\t<th class=\"data\">{$lang['strcomment']}</th>\n";
1032
            echo "\t\t<td class=\"data1\"><textarea cols=\"32\" rows=\"3\"name=\"formComment\">", htmlspecialchars($_POST['formComment']), "</textarea></td>\n";
1033
            echo "\t</tr>\n";
1034
            echo "</table>\n";
1035
            echo "<p><input type=\"hidden\" name=\"action\" value=\"alterdict\" />\n";
1036
            echo '<input type="hidden" name="ftsdict" value="', htmlspecialchars($_POST['ftsdict']), "\" />\n";
1037
            echo "<input type=\"hidden\" name=\"prev_action\" value=\"viewdicts\" /></p>\n";
1038
            echo $misc->form;
1039
            echo "<input type=\"submit\" name=\"alter\" value=\"{$lang['stralter']}\" />\n";
1040
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
1041
            echo "</form>\n";
1042
        } else {
1043
            echo "<p>{$lang['strnodata']}</p>\n";
1044
        }
1045
    }
1046
1047
    /**
1048
     * Save the form submission containing changes to a FTS dictionary
1049
     */
1050
    public function doSaveAlterDict()
0 ignored issues
show
Coding Style introduced by
doSaveAlterDict uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1051
    {
1052
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
1053
        $misc = $this->misc;
1054
        $lang = $this->lang;
1055
        $data = $misc->getDatabaseAccessor();
1056
1057
        $status = $data->updateFtsDictionary($_POST['ftsdict'], $_POST['formComment'], $_POST['formName']);
1058
        if ($status == 0) {
1059
            $this->doViewDicts($lang['strftsdictaltered']);
1060
        } else {
1061
            $this->doAlterDict($lang['strftsdictalteredbad']);
1062
        }
1063
    }
1064
1065
    /**
1066
     * Show confirmation of drop and perform actual drop of FTS mapping
1067
     */
1068
    public function doDropMapping($confirm)
0 ignored issues
show
Coding Style introduced by
doDropMapping uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1069
    {
1070
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
1071
        $misc = $this->misc;
1072
        $lang = $this->lang;
1073
        $data = $misc->getDatabaseAccessor();
1074
1075
        if (empty($_REQUEST['mapping']) && empty($_REQUEST['ma'])) {
1076
            $this->doDefault($lang['strftsspecifymappingtodrop']);
1077
            return;
1078
        }
1079
1080
        if (empty($_REQUEST['ftscfg'])) {
1081
            $this->doDefault($lang['strftsspecifyconfigtoalter']);
1082
            return;
1083
        }
1084
1085
        if ($confirm) {
1086
            $this->printTrail('ftscfg'); // TODO: proper breadcrumbs
1087
            $this->printTitle($lang['strdrop'], 'pg.ftscfg.alter');
1088
1089
            echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
1090
1091
            // Case of multiaction drop
1092
            if (isset($_REQUEST['ma'])) {
1093
                foreach ($_REQUEST['ma'] as $v) {
1094
                    $a = unserialize(htmlspecialchars_decode($v, ENT_QUOTES));
0 ignored issues
show
Security introduced by
htmlspecialchars_decode(...\Controller\ENT_QUOTES) can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_REQUEST, and $_REQUEST['ma'] is assigned to $v
    in src/controllers/FulltextController.php on line 1093
  2. Data is passed through htmlspecialchars_decode()
    in src/controllers/FulltextController.php on line 1094

Preventing Object Injection Attacks

If you pass raw user-data to unserialize() for example, this can be used to create an object of any class that is available in your local filesystem. For an attacker, classes that have magic methods like __destruct or __wakeup are particularly interesting in such a case, as they can be exploited very easily.

We recommend to not pass user data to such a function. In case of unserialize, better use JSON to transfer data.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1095
                    echo '<p>', sprintf($lang['strconfdropftsmapping'], $misc->printVal($a['mapping']), $misc->printVal($_REQUEST['ftscfg'])), "</p>\n";
1096
                    printf('<input type="hidden" name="mapping[]" value="%s" />', htmlspecialchars($a['mapping']));
1097
                }
1098
            } else {
1099
                echo '<p>', sprintf($lang['strconfdropftsmapping'], $misc->printVal($_REQUEST['mapping']), $misc->printVal($_REQUEST['ftscfg'])), "</p>\n";
1100
                echo '<input type="hidden" name="mapping" value="', htmlspecialchars($_REQUEST['mapping']), "\" />\n";
1101
            }
1102
1103
            echo "<input type=\"hidden\" name=\"ftscfg\" value=\"{$_REQUEST['ftscfg']}\" />\n";
1104
            echo "<input type=\"hidden\" name=\"action\" value=\"dropmapping\" />\n";
1105
            echo "<input type=\"hidden\" name=\"prev_action\" value=\"viewconfig\" /></p>\n";
1106
            echo $misc->form;
1107
            echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n";
1108
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />\n";
1109
            echo "</form>\n";
1110
        } else {
1111
            // Case of multiaction drop
1112
            if (is_array($_REQUEST['mapping'])) {
1113
                $status = $data->changeFtsMapping($_REQUEST['ftscfg'], $_REQUEST['mapping'], 'drop');
1114
                if ($status != 0) {
1115
                    $this->doViewConfig($_REQUEST['ftscfg'], $lang['strftsmappingdroppedbad']);
1116
                    return;
1117
                }
1118
                $this->doViewConfig($_REQUEST['ftscfg'], $lang['strftsmappingdropped']);
1119
            } else {
1120
                $status = $data->changeFtsMapping($_REQUEST['ftscfg'], [$_REQUEST['mapping']], 'drop');
1121
                if ($status == 0) {
1122
                    $this->doViewConfig($_REQUEST['ftscfg'], $lang['strftsmappingdropped']);
1123
                } else {
1124
                    $this->doViewConfig($_REQUEST['ftscfg'], $lang['strftsmappingdroppedbad']);
1125
                }
1126
            }
1127
        }
1128
    }
1129
1130
    public function doAlterMapping($msg = '')
0 ignored issues
show
Coding Style introduced by
doAlterMapping uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doAlterMapping uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1131
    {
1132
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
1133
        $misc = $this->misc;
1134
        $lang = $this->lang;
1135
        $data = $misc->getDatabaseAccessor();
1136
        $this->printTrail('ftscfg');
1137
        $this->printTitle($lang['stralter'], 'pg.ftscfg.alter');
1138
        $this->printMsg($msg);
1139
1140
        $ftsdicts = $data->getFtsDictionaries();
1141
        if ($ftsdicts->recordCount() > 0) {
1142
            if (!isset($_POST['formMapping'])) {
1143
                $_POST['formMapping'] = @$_REQUEST['mapping'];
1144
            }
1145
1146
            if (!isset($_POST['formDictionary'])) {
1147
                $_POST['formDictionary'] = '';
1148
            }
1149
1150
            if (!isset($_POST['ftscfg'])) {
1151
                $_POST['ftscfg'] = $_REQUEST['ftscfg'];
1152
            }
1153
1154
            echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
1155
1156
            echo "<table>\n";
1157
            echo "\t<tr>\n";
1158
            echo "\t\t<th class=\"data left required\">{$lang['strftsmapping']}</th>\n";
1159
            echo "\t\t<td class=\"data1\">";
1160
1161
            // Case of multiaction drop
1162
            if (isset($_REQUEST['ma'])) {
1163
                $ma_mappings       = [];
1164
                $ma_mappings_names = [];
1165
                foreach ($_REQUEST['ma'] as $v) {
1166
                    $a = unserialize(htmlspecialchars_decode($v, ENT_QUOTES));
0 ignored issues
show
Security introduced by
htmlspecialchars_decode(...\Controller\ENT_QUOTES) can contain request data and is used in unserialized context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_REQUEST, and $_REQUEST['ma'] is assigned to $v
    in src/controllers/FulltextController.php on line 1165
  2. Data is passed through htmlspecialchars_decode()
    in src/controllers/FulltextController.php on line 1166

Preventing Object Injection Attacks

If you pass raw user-data to unserialize() for example, this can be used to create an object of any class that is available in your local filesystem. For an attacker, classes that have magic methods like __destruct or __wakeup are particularly interesting in such a case, as they can be exploited very easily.

We recommend to not pass user data to such a function. In case of unserialize, better use JSON to transfer data.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1167
                    printf('<input type="hidden" name="formMapping[]" value="%s" />', htmlspecialchars($a['mapping']));
1168
                    $ma_mappings[]       = $data->getFtsMappingByName($_POST['ftscfg'], $a['mapping']);
1169
                    $ma_mappings_names[] = $a['mapping'];
1170
                }
1171
                echo implode(', ', $ma_mappings_names);
0 ignored issues
show
Security introduced by
implode(', ', $ma_mappings_names) can contain request data and is used in output context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_REQUEST, and $_REQUEST['ma'] is assigned to $v
    in src/controllers/FulltextController.php on line 1165
  2. Data is passed through htmlspecialchars_decode(), and Data is passed through unserialize(), and unserialize(htmlspecialchars_decode($v, PHPPgAdmin\Controller\ENT_QUOTES)) is assigned to $a
    in src/controllers/FulltextController.php on line 1166
  3. $a['mapping'] is assigned to $ma_mappings_names
    in src/controllers/FulltextController.php on line 1169
  4. Data is passed through implode()
    in src/controllers/FulltextController.php on line 1171

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
1172
            } else {
1173
                $mapping = $data->getFtsMappingByName($_POST['ftscfg'], $_POST['formMapping']);
1174
                echo $mapping->fields['name'];
1175
                echo '<input type="hidden" name="formMapping" value="', htmlspecialchars($_POST['formMapping']), "\" />\n";
1176
            }
1177
1178
            echo "\t\t</td>\n";
1179
            echo "\t</tr>\n";
1180
1181
            // Dictionary
1182
            echo "\t<tr>\n";
1183
            echo "\t\t<th class=\"data left required\">{$lang['strftsdict']}</th>\n";
1184
            echo "\t\t<td class=\"data1\">";
1185
            echo "\t\t\t<select name=\"formDictionary\">\n";
1186
            while (!$ftsdicts->EOF) {
1187
                $ftsdict = htmlspecialchars($ftsdicts->fields['name']);
1188
                echo "\t\t\t\t<option value=\"{$ftsdict}\"",
1189
                ($ftsdict == $_POST['formDictionary'] || $ftsdict == @$mapping->fields['dictionaries'] || $ftsdict == @$ma_mappings[0]->fields['dictionaries']) ? ' selected="selected"' : '', ">{$ftsdict}</option>\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ma_mappings does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $mapping does not seem to be defined for all execution paths leading up to this point.
Loading history...
1190
                $ftsdicts->moveNext();
1191
            }
1192
1193
            echo "\t\t</td>\n";
1194
            echo "\t</tr>\n";
1195
1196
            echo "</table>\n";
1197
            echo "<p><input type=\"hidden\" name=\"action\" value=\"altermapping\" />\n";
1198
            echo '<input type="hidden" name="ftscfg" value="', htmlspecialchars($_POST['ftscfg']), "\" />\n";
1199
            echo "<input type=\"hidden\" name=\"prev_action\" value=\"viewconfig\" /></p>\n";
1200
1201
            echo $misc->form;
1202
            echo "<input type=\"submit\" name=\"alter\" value=\"{$lang['stralter']}\" />\n";
1203
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
1204
            echo "</form>\n";
1205
        } else {
1206
            echo "<p>{$lang['strftsnodictionaries']}</p>\n";
1207
        }
1208
    }
1209
1210
    /**
1211
     * Save the form submission containing changes to a FTS mapping
1212
     */
1213 View Code Duplication
    public function doSaveAlterMapping()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
doSaveAlterMapping uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1214
    {
1215
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
1216
        $misc = $this->misc;
1217
        $lang = $this->lang;
1218
        $data = $misc->getDatabaseAccessor();
1219
1220
        $mappingArray = (is_array($_POST['formMapping']) ? $_POST['formMapping'] : [$_POST['formMapping']]);
1221
        $status       = $data->changeFtsMapping($_POST['ftscfg'], $mappingArray, 'alter', $_POST['formDictionary']);
1222
        if ($status == 0) {
1223
            $this->doViewConfig($_POST['ftscfg'], $lang['strftsmappingaltered']);
1224
        } else {
1225
            $this->doAlterMapping($lang['strftsmappingalteredbad']);
1226
        }
1227
    }
1228
1229
    /**
1230
     * Show the form to enter parameters of a new FTS mapping
1231
     */
1232
    public function doAddMapping($msg = '')
0 ignored issues
show
Coding Style introduced by
doAddMapping uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
doAddMapping uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1233
    {
1234
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
1235
        $misc = $this->misc;
1236
        $lang = $this->lang;
1237
        $data = $misc->getDatabaseAccessor();
1238
1239
        $this->printTrail('ftscfg');
1240
        $this->printTitle($lang['stralter'], 'pg.ftscfg.alter');
1241
        $this->printMsg($msg);
1242
1243
        $ftsdicts = $data->getFtsDictionaries();
1244
        if ($ftsdicts->recordCount() > 0) {
1245
            if (!isset($_POST['formMapping'])) {
1246
                $_POST['formMapping'] = '';
1247
            }
1248
1249
            if (!isset($_POST['formDictionary'])) {
1250
                $_POST['formDictionary'] = '';
1251
            }
1252
1253
            if (!isset($_POST['ftscfg'])) {
1254
                $_POST['ftscfg'] = $_REQUEST['ftscfg'];
1255
            }
1256
1257
            $mappings = $data->getFtsMappings($_POST['ftscfg']);
1258
1259
            echo '<form action="' . SUBFOLDER . "/src/views/fulltext.php\" method=\"post\">\n";
1260
            echo "<table>\n";
1261
            echo "\t<tr>\n";
1262
            echo "\t\t<th class=\"data left required\">{$lang['strftsmapping']}</th>\n";
1263
            echo "\t\t<td class=\"data1\">";
1264
            echo "\t\t\t<select name=\"formMapping\">\n";
1265
            while (!$mappings->EOF) {
1266
                $mapping      = htmlspecialchars($mappings->fields['name']);
1267
                $mapping_desc = htmlspecialchars($mappings->fields['description']);
1268
                echo "\t\t\t\t<option value=\"{$mapping}\"",
1269
                $mapping == $_POST['formMapping'] ? ' selected="selected"' : '', ">{$mapping}", $mapping_desc ? " - {$mapping_desc}" : '', "</option>\n";
1270
                $mappings->moveNext();
1271
            }
1272
            echo "\t\t</td>\n";
1273
            echo "\t</tr>\n";
1274
1275
            // Dictionary
1276
            echo "\t<tr>\n";
1277
            echo "\t\t<th class=\"data left required\">{$lang['strftsdict']}</th>\n";
1278
            echo "\t\t<td class=\"data1\">";
1279
            echo "\t\t\t<select name=\"formDictionary\">\n";
1280
            while (!$ftsdicts->EOF) {
1281
                $ftsdict = htmlspecialchars($ftsdicts->fields['name']);
1282
                echo "\t\t\t\t<option value=\"{$ftsdict}\"",
1283
                $ftsdict == $_POST['formDictionary'] ? ' selected="selected"' : '', ">{$ftsdict}</option>\n";
1284
                $ftsdicts->moveNext();
1285
            }
1286
1287
            echo "\t\t</td>\n";
1288
            echo "\t</tr>\n";
1289
1290
            echo "</table>\n";
1291
            echo "<p><input type=\"hidden\" name=\"action\" value=\"addmapping\" />\n";
1292
            echo '<input type="hidden" name="ftscfg" value="', htmlspecialchars($_POST['ftscfg']), "\" />\n";
1293
            echo "<input type=\"hidden\" name=\"prev_action\" value=\"viewconfig\" /></p>\n";
1294
            echo $misc->form;
1295
            echo "<input type=\"submit\" name=\"add\" value=\"{$lang['stradd']}\" />\n";
1296
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n";
1297
            echo "</form>\n";
1298
        } else {
1299
            echo "<p>{$lang['strftsnodictionaries']}</p>\n";
1300
        }
1301
    }
1302
1303
    /**
1304
     * Save the form submission containing parameters of a new FTS mapping
1305
     */
1306 View Code Duplication
    public function doSaveAddMapping()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
doSaveAddMapping uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1307
    {
1308
        $conf = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
1309
        $misc = $this->misc;
1310
        $lang = $this->lang;
1311
        $data = $misc->getDatabaseAccessor();
1312
1313
        $mappingArray = (is_array($_POST['formMapping']) ? $_POST['formMapping'] : [$_POST['formMapping']]);
1314
        $status       = $data->changeFtsMapping($_POST['ftscfg'], $mappingArray, 'add', $_POST['formDictionary']);
1315
        if ($status == 0) {
1316
            $this->doViewConfig($_POST['ftscfg'], $lang['strftsmappingadded']);
1317
        } else {
1318
            $this->doAddMapping($lang['strftsmappingaddedbad']);
1319
        }
1320
    }
1321
}
1322