Issues (217)

src/controllers/SchemasController.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * PHPPgAdmin 6.1.3
5
 */
6
7
namespace PHPPgAdmin\Controller;
8
9
use PHPPgAdmin\Decorators\Decorator;
10
11
/**
12
 * Base controller class.
13
 */
14
class SchemasController extends BaseController
15
{
16
    use \PHPPgAdmin\Traits\ExportTrait;
0 ignored issues
show
The trait PHPPgAdmin\Traits\ExportTrait requires the property $subFolder which is not provided by PHPPgAdmin\Controller\SchemasController.
Loading history...
17
18
    public $controller_title = 'strschemas';
19
20
    /**
21
     * Default method to render the controller according to the action parameter.
22
     */
23
    public function render()
24
    {
25
        if ('tree' === $this->action) {
26
            return $this->doTree();
27
        }
28
29
        if ('subtree' === $this->action) {
30
            return $this->doSubTree();
31
        }
32
33
        if (null !== $this->getPostParam('cancel')) {
34
            $this->action = '';
35
        }
36
37
        $header_template = 'header.twig';
38
39
        \ob_start();
40
41
        switch ($this->action) {
42
            case 'create':
43
                if (null !== $this->getPostParam('create')) {
44
                    $this->doSaveCreate();
45
                } else {
46
                    $this->doCreate();
47
                }
48
49
                break;
50
            case 'alter':
51
                if (null !== $this->getPostParam('alter')) {
52
                    $this->doSaveAlter();
53
                } else {
54
                    $this->doAlter();
55
                }
56
57
                break;
58
            case 'drop':
59
                if (null !== $this->getPostParam('drop')) {
60
                    $this->doDrop(false);
61
                } else {
62
                    $this->doDrop(true);
63
                }
64
65
                break;
66
            case 'export':
67
                $this->doExport();
68
69
                break;
70
71
            default:
72
                $header_template = 'header_datatables.twig';
73
                $this->doDefault();
74
75
                break;
76
        }
77
78
        $output = \ob_get_clean();
79
80
        $this->printHeader($this->headerTitle(), null, true, $header_template);
81
        $this->printBody();
82
83
        echo $output;
84
85
        return $this->printFooter();
86
    }
87
88
    /**
89
     * Show default list of schemas in the database.
90
     *
91
     * @param mixed $msg
92
     */
93
    public function doDefault($msg = ''): void
94
    {
95
        $data = $this->misc->getDatabaseAccessor();
96
97
        $this->printTrail('database');
98
        $this->printTabs('database', 'schemas');
99
        $this->printMsg($msg);
100
101
        // Check that the DB actually supports schemas
102
        $schemas = $data->getSchemas();
103
        $destination = $this->container->getDestinationWithLastTab('schema');
104
105
        $columns = [
106
            'schema' => [
107
                'title' => $this->lang['strschema'],
108
                'field' => Decorator::field('nspname'),
109
                'url' => \containerInstance()->subFolder . "{$destination}&amp;",
110
                'vars' => ['schema' => 'nspname'],
111
            ],
112
            'owner' => [
113
                'title' => $this->lang['strowner'],
114
                'field' => Decorator::field('nspowner'),
115
            ],
116
            'schema_size' => [
117
                'title' => $this->lang['strsize'],
118
                'field' => Decorator::field('schema_size'),
119
            ],
120
            'actions' => [
121
                'title' => $this->lang['stractions'],
122
            ],
123
            'comment' => [
124
                'title' => $this->lang['strcomment'],
125
                'field' => Decorator::field('nspcomment'),
126
            ],
127
        ];
128
129
        $actions = [
130
            'multiactions' => [
131
                'keycols' => ['nsp' => 'nspname'],
132
                'url' => 'schemas',
133
            ],
134
            'drop' => [
135
                'content' => $this->lang['strdrop'],
136
                'attr' => [
137
                    'href' => [
138
                        'url' => 'schemas',
139
                        'urlvars' => [
140
                            'action' => 'drop',
141
                            'nsp' => Decorator::field('nspname'),
142
                        ],
143
                    ],
144
                ],
145
                'multiaction' => 'drop',
146
            ],
147
            'privileges' => [
148
                'content' => $this->lang['strprivileges'],
149
                'attr' => [
150
                    'href' => [
151
                        'url' => 'privileges',
152
                        'urlvars' => [
153
                            'subject' => 'schema',
154
                            'schema' => Decorator::field('nspname'),
155
                        ],
156
                    ],
157
                ],
158
            ],
159
            'alter' => [
160
                'content' => $this->lang['stralter'],
161
                'attr' => [
162
                    'href' => [
163
                        'url' => 'schemas',
164
                        'urlvars' => [
165
                            'action' => 'alter',
166
                            'schema' => Decorator::field('nspname'),
167
                        ],
168
                    ],
169
                ],
170
            ],
171
        ];
172
173
        if (!$data->hasAlterSchema()) {
174
            unset($actions['alter']);
175
        }
176
177
        echo $this->printTable($schemas, $columns, $actions, 'schemas-schemas', $this->lang['strnoschemas']);
178
179
        $this->printNavLinks(['create' => [
180
            'attr' => [
181
                'href' => [
182
                    'url' => 'schemas',
183
                    'urlvars' => [
184
                        'action' => 'create',
185
                        'server' => $_REQUEST['server'],
186
                        'database' => $_REQUEST['database'],
187
                    ],
188
                ],
189
            ],
190
            'content' => $this->lang['strcreateschema'],
191
        ]], 'schemas-schemas', \get_defined_vars());
192
    }
193
194
    /**
195
     * Generate XML for the browser tree.
196
     */
197
    public function doTree()
198
    {
199
        $data = $this->misc->getDatabaseAccessor();
200
201
        $schemas = $data->getSchemas();
202
203
        $reqvars = $this->misc->getRequestVars('schema');
204
205
        $attrs = [
206
            'text' => Decorator::field('nspname'),
207
            'icon' => 'Schema',
208
            'toolTip' => Decorator::field('nspcomment'),
209
            'action' => Decorator::redirecturl(
210
                'redirect',
211
                $reqvars,
212
                [
213
                    'subject' => 'schema',
214
                    'schema' => Decorator::field('nspname'),
215
                ]
216
            ),
217
            'branch' => Decorator::url(
218
                'schemas',
219
                $reqvars,
220
                [
221
                    'action' => 'subtree',
222
                    'schema' => Decorator::field('nspname'),
223
                ]
224
            ),
225
        ];
226
227
        return $this->printTree($schemas, $attrs, 'schemas');
228
    }
229
230
    public function doSubTree()
231
    {
232
        $tabs = $this->misc->getNavTabs('schema');
233
234
        $items = $this->adjustTabsForTree($tabs);
235
236
        $reqvars = $this->misc->getRequestVars('schema');
237
238
        $attrs = [
239
            'text' => Decorator::field('title'),
240
            'icon' => Decorator::field('icon'),
241
            'action' => Decorator::actionurl(
242
                Decorator::field('url'),
243
                $reqvars,
244
                Decorator::field('urlvars', [])
245
            ),
246
            'branch' => Decorator::url(
247
                Decorator::field('url'),
248
                $reqvars,
249
                Decorator::field('urlvars'),
250
                ['action' => 'tree']
251
            ),
252
        ];
253
254
        return $this->printTree($items, $attrs, 'schema');
255
    }
256
257
    /**
258
     * Displays a screen where they can enter a new schema.
259
     *
260
     * @param mixed $msg
261
     */
262
    public function doCreate($msg = ''): void
263
    {
264
        $data = $this->misc->getDatabaseAccessor();
265
266
        $server_info = $this->misc->getServerInfo();
267
268
        $this->coalesceArr($_POST, 'formName', '');
269
270
        $this->coalesceArr($_POST, 'formAuth', $server_info['username']);
271
272
        $this->coalesceArr($_POST, 'formSpc', '');
273
274
        $this->coalesceArr($_POST, 'formComment', '');
275
276
        // Fetch all users from the database
277
        $users = $data->getUsers();
278
279
        $this->printTrail('database');
280
        $this->printTitle($this->lang['strcreateschema'], 'pg.schema.create');
281
        $this->printMsg($msg);
282
283
        echo '<form action="' . \containerInstance()->subFolder . '/src/views/schemas" method="post">' . \PHP_EOL;
284
        echo '<table style="width: 100%">' . \PHP_EOL;
285
        echo "\t<tr>\n\t\t<th class=\"data left required\">{$this->lang['strname']}</th>" . \PHP_EOL;
286
        echo "\t\t<td class=\"data1\"><input name=\"formName\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
287
        \htmlspecialchars($_POST['formName']), "\" /></td>\n\t</tr>" . \PHP_EOL;
288
        // Owner
289
        echo "\t<tr>\n\t\t<th class=\"data left required\">{$this->lang['strowner']}</th>" . \PHP_EOL;
290
        echo "\t\t<td class=\"data1\">\n\t\t\t<select name=\"formAuth\">" . \PHP_EOL;
291
292
        while (!$users->EOF) {
293
            $uname = \htmlspecialchars($users->fields['usename']);
294
            echo "\t\t\t\t<option value=\"{$uname}\"",
295
            ($uname === $_POST['formAuth']) ? ' selected="selected"' : '', ">{$uname}</option>" . \PHP_EOL;
296
            $users->moveNext();
297
        }
298
        echo "\t\t\t</select>\n\t\t</td>\n\t</tr>" . \PHP_EOL;
299
        echo "\t<tr>\n\t\t<th class=\"data left\">{$this->lang['strcomment']}</th>" . \PHP_EOL;
300
        echo "\t\t<td class=\"data1\"><textarea name=\"formComment\" rows=\"3\" cols=\"32\">",
301
        \htmlspecialchars($_POST['formComment']), "</textarea></td>\n\t</tr>" . \PHP_EOL;
302
303
        echo '</table>' . \PHP_EOL;
304
        echo '<p>' . \PHP_EOL;
305
        echo '<input type="hidden" name="action" value="create" />' . \PHP_EOL;
306
        echo '<input type="hidden" name="database" value="', \htmlspecialchars($_REQUEST['database']), '" />' . \PHP_EOL;
307
        echo $this->view->form;
308
        echo "<input type=\"submit\" name=\"create\" value=\"{$this->lang['strcreate']}\" />" . \PHP_EOL;
309
        echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" />" . \PHP_EOL;
310
        echo '</p>' . \PHP_EOL;
311
        echo '</form>' . \PHP_EOL;
312
    }
313
314
    /**
315
     * Actually creates the new schema in the database.
316
     */
317
    public function doSaveCreate(): void
318
    {
319
        $data = $this->misc->getDatabaseAccessor();
320
321
        // Check that they've given a name
322
        if ('' === $_POST['formName']) {
323
            $this->doCreate($this->lang['strschemaneedsname']);
324
        } else {
325
            $status = $data->createSchema($_POST['formName'], $_POST['formAuth'], $_POST['formComment']);
326
327
            if (0 === $status) {
328
                $this->view->setReloadBrowser(true);
329
                $this->doDefault($this->lang['strschemacreated']);
330
            } else {
331
                $this->doCreate($this->lang['strschemacreatedbad']);
332
            }
333
        }
334
    }
335
336
    /**
337
     * Display a form to permit editing schema properies.
338
     * TODO: permit changing owner.
339
     *
340
     * @param mixed $msg
341
     */
342
    public function doAlter($msg = ''): void
343
    {
344
        $data = $this->misc->getDatabaseAccessor();
345
346
        $this->printTrail('schema');
347
        $this->printTitle($this->lang['stralter'], 'pg.schema.alter');
348
        $this->printMsg($msg);
349
350
        $schema = $data->getSchemaByName($_REQUEST['schema']);
351
352
        if (0 < $schema->recordCount()) {
353
            $this->coalesceArr($_POST, 'comment', $schema->fields['nspcomment']);
354
355
            $this->coalesceArr($_POST, 'schema', $_REQUEST['schema']);
356
357
            $this->coalesceArr($_POST, 'name', $_REQUEST['schema']);
358
359
            $this->coalesceArr($_POST, 'owner', $schema->fields['ownername']);
360
361
            echo '<form action="' . \containerInstance()->subFolder . '/src/views/schemas" method="post">' . \PHP_EOL;
362
            echo '<table>' . \PHP_EOL;
363
364
            echo "\t<tr>" . \PHP_EOL;
365
            echo "\t\t<th class=\"data left required\">{$this->lang['strname']}</th>" . \PHP_EOL;
366
            echo "\t\t<td class=\"data1\">";
367
            echo "\t\t\t<input name=\"name\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"",
368
            \htmlspecialchars($_POST['name']), '" />' . \PHP_EOL;
369
            echo "\t\t</td>" . \PHP_EOL;
370
            echo "\t</tr>" . \PHP_EOL;
371
372
            if ($data->hasAlterSchemaOwner()) {
373
                $users = $data->getUsers();
374
                echo "<tr><th class=\"data left required\">{$this->lang['strowner']}</th>" . \PHP_EOL;
375
                echo '<td class="data2"><select name="owner">';
376
377
                while (!$users->EOF) {
378
                    $uname = $users->fields['usename'];
379
                    echo '<option value="', \htmlspecialchars($uname), '"',
380
                    ($uname === $_POST['owner']) ? ' selected="selected"' : '', '>', \htmlspecialchars($uname), '</option>' . \PHP_EOL;
381
                    $users->moveNext();
382
                }
383
                echo '</select></td></tr>' . \PHP_EOL;
384
            } else {
385
                echo "<input name=\"owner\" value=\"{$_POST['owner']}\" type=\"hidden\" />";
386
            }
387
388
            echo "\t<tr>" . \PHP_EOL;
389
            echo "\t\t<th class=\"data\">{$this->lang['strcomment']}</th>" . \PHP_EOL;
390
            echo "\t\t<td class=\"data1\"><textarea cols=\"32\" rows=\"3\" name=\"comment\">", \htmlspecialchars($_POST['comment']), '</textarea></td>' . \PHP_EOL;
391
            echo "\t</tr>" . \PHP_EOL;
392
            echo '</table>' . \PHP_EOL;
393
            echo '<p><input type="hidden" name="action" value="alter" />' . \PHP_EOL;
394
            echo '<input type="hidden" name="schema" value="', \htmlspecialchars($_POST['schema']), '" />' . \PHP_EOL;
395
            echo $this->view->form;
396
            echo "<input type=\"submit\" name=\"alter\" value=\"{$this->lang['stralter']}\" />" . \PHP_EOL;
397
            echo \sprintf('<input type="submit" name="cancel" value="%s"  /></p>%s', $this->lang['strcancel'], \PHP_EOL);
398
            echo '</form>' . \PHP_EOL;
399
        } else {
400
            echo "<p>{$this->lang['strnodata']}</p>" . \PHP_EOL;
401
        }
402
    }
403
404
    /**
405
     * Save the form submission containing changes to a schema.
406
     *
407
     * @param mixed $msg
408
     */
409
    public function doSaveAlter(): void
410
    {
411
        $data = $this->misc->getDatabaseAccessor();
412
413
        $status = $data->updateSchema($_POST['schema'], $_POST['comment'], $_POST['name'], $_POST['owner']);
414
415
        if (0 === $status) {
416
            $this->view->setReloadBrowser(true);
417
            $this->doDefault($this->lang['strschemaaltered']);
418
        } else {
419
            $this->doAlter($this->lang['strschemaalteredbad']);
420
        }
421
    }
422
423
    /**
424
     * Show confirmation of drop and perform actual drop.
425
     *
426
     * @param mixed $confirm
427
     */
428
    public function doDrop($confirm)
429
    {
430
        $data = $this->misc->getDatabaseAccessor();
431
432
        if (empty($_REQUEST['nsp']) && empty($_REQUEST['ma'])) {
433
            return $this->doDefault($this->lang['strspecifyschematodrop']);
434
        }
435
436
        if ($confirm) {
437
            $this->printTrail('schema');
438
            $this->printTitle($this->lang['strdrop'], 'pg.schema.drop');
439
440
            echo '<form action="' . \containerInstance()->subFolder . '/src/views/schemas" method="post">' . \PHP_EOL;
441
            //If multi drop
442
            if (isset($_REQUEST['ma'])) {
443
                foreach ($_REQUEST['ma'] as $v) {
444
                    $a = \unserialize(\htmlspecialchars_decode($v, \ENT_QUOTES));
445
                    echo '<p>', \sprintf($this->lang['strconfdropschema'], $this->misc->printVal($a['nsp'])), '</p>' . \PHP_EOL;
446
                    echo '<input type="hidden" name="nsp[]" value="', \htmlspecialchars($a['nsp']), '" />' . \PHP_EOL;
447
                }
448
            } else {
449
                echo '<p>', \sprintf($this->lang['strconfdropschema'], $this->misc->printVal($_REQUEST['nsp'])), '</p>' . \PHP_EOL;
450
                echo '<input type="hidden" name="nsp" value="', \htmlspecialchars($_REQUEST['nsp']), '" />' . \PHP_EOL;
451
            }
452
453
            echo "<p><input type=\"checkbox\" id=\"cascade\" name=\"cascade\" /> <label for=\"cascade\">{$this->lang['strcascade']}</label></p>" . \PHP_EOL;
454
            echo '<p><input type="hidden" name="action" value="drop" />' . \PHP_EOL;
455
            echo '<input type="hidden" name="database" value="', \htmlspecialchars($_REQUEST['database']), '" />' . \PHP_EOL;
456
            echo $this->view->form;
457
            echo "<input type=\"submit\" name=\"drop\" value=\"{$this->lang['strdrop']}\" />" . \PHP_EOL;
458
            echo \sprintf('<input type="submit" name="cancel" value="%s"  /></p>%s', $this->lang['strcancel'], \PHP_EOL);
459
            echo '</form>' . \PHP_EOL;
460
        } else {
461
            if (\is_array($_POST['nsp'])) {
462
                $msg = '';
463
                $status = $data->beginTransaction();
464
465
                if (0 === $status) {
466
                    foreach ($_POST['nsp'] as $s) {
467
                        $status = $data->dropSchema($s, isset($_POST['cascade']));
468
469
                        if (0 === $status) {
470
                            $msg .= \sprintf(
471
                                '%s: %s<br />',
472
                                \htmlentities($s, \ENT_QUOTES, 'UTF-8'),
473
                                $this->lang['strschemadropped']
474
                            );
475
                        } else {
476
                            $data->endTransaction();
477
                            $this->doDefault(\sprintf(
478
                                '%s%s: %s<br />',
479
                                $msg,
480
                                \htmlentities($s, \ENT_QUOTES, 'UTF-8'),
481
                                $this->lang['strschemadroppedbad']
482
                            ));
483
484
                            return;
485
                        }
486
                    }
487
                }
488
489
                if (0 === $data->endTransaction()) {
490
                    // Everything went fine, back to the Default page....
491
                    $this->view->setReloadBrowser(true);
492
                    $this->doDefault($msg);
493
                } else {
494
                    $this->doDefault($this->lang['strschemadroppedbad']);
495
                }
496
            } else {
497
                $status = $data->dropSchema($_POST['nsp'], isset($_POST['cascade']));
498
499
                if (0 === $status) {
500
                    $this->view->setReloadBrowser(true);
501
                    $this->doDefault($this->lang['strschemadropped']);
502
                } else {
503
                    $this->doDefault($this->lang['strschemadroppedbad']);
504
                }
505
            }
506
        }
507
    }
508
509
    /**
510
     * Displays options for database download.
511
     *
512
     * @param mixed $msg
513
     */
514
    public function doExport($msg = ''): void
515
    {
516
        $this->printTrail('schema');
517
        $this->printTabs('schema', 'export');
518
        $this->printMsg($msg);
519
520
        $subject = 'schema';
521
        $object = $_REQUEST['schema'];
522
523
        echo $this->formHeader('dbexport');
524
525
        echo $this->dataOnly(true, true);
526
527
        echo $this->structureOnly();
528
529
        echo $this->structureAndData(true);
530
531
        echo $this->displayOrDownload(!(\mb_strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE') && isset($_SERVER['HTTPS'])));
532
533
        echo $this->formFooter($subject, $object);
534
    }
535
}
536