Passed
Push — master ( 442876...4ec1bc )
by Felipe
15:55 queued 10:33
created

DisplayController::doBrowseFK()   B

Complexity

Conditions 4

Size

Total Lines 46
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 29
nop 0
dl 0
loc 46
rs 8.6315
c 0
b 0
f 0
1
<?php
2
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
/*
4
 * PHPPgAdmin v6.0.0-beta.30
5
 */
6
7
namespace PHPPgAdmin\Controller;
8
9
/**
10
 * Base controller class.
11
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
12
class DisplayController extends BaseController
13
{
14
    public $controller_name = 'DisplayController';
15
16
    /**
17
     * Default method to render the controller according to the action parameter.
18
     */
19
    public function render()
20
    {
21
        $conf           = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
22
        $this->misc     = $this->misc;
23
        $lang           = $this->lang;
24
        $plugin_manager = $this->plugin_manager;
1 ignored issue
show
Unused Code introduced by
The assignment to $plugin_manager is dead and can be removed.
Loading history...
25
        $action         = $this->action;
26
27
        if ('dobrowsefk' == $action) {
28
            return $this->doBrowseFK();
29
        }
30
31
        set_time_limit(0);
32
33
        $scripts = '<script src="' . \SUBFOLDER . '/js/display.js" type="text/javascript"></script>';
34
35
        $scripts .= '<script type="text/javascript">' . "\n";
36
        $scripts .= "var Display = {\n";
37
        $scripts .= "errmsg: '" . str_replace("'", "\\'", $lang['strconnectionfail']) . "'\n";
38
        $scripts .= "};\n";
39
        $scripts .= '</script>' . "\n";
40
41
        $footer_template = 'footer.twig';
42
        $header_template = 'header.twig';
43
44
        ob_start();
45
        switch ($action) {
46
            case 'editrow':
47
                $header_template = 'header_sqledit.twig';
48
                $footer_template = 'footer_sqledit.twig';
49
                if (isset($_POST['save'])) {
50
                    $this->doEditRow(false);
51
                } else {
52
                    $this->doBrowse();
53
                }
54
55
                break;
56
            case 'confeditrow':
57
                $this->doEditRow(true);
58
59
                break;
60
            case 'delrow':
61
                $header_template = 'header_sqledit.twig';
62
                $footer_template = 'footer_sqledit.twig';
63
                if (isset($_POST['yes'])) {
64
                    $this->doDelRow(false);
65
                } else {
66
                    $this->doBrowse();
67
                }
68
69
                break;
70
            case 'confdelrow':
71
                $this->doDelRow(true);
72
73
                break;
74
            default:
75
                $header_template = 'header_sqledit.twig';
76
                $footer_template = 'footer_sqledit.twig';
77
                $this->doBrowse();
78
79
                break;
80
        }
81
        $output = ob_get_clean();
82
83
        // Set the title based on the subject of the request
84
        if (isset($_REQUEST['subject'], $_REQUEST[$_REQUEST['subject']])) {
85
            if ('table' == $_REQUEST['subject']) {
86
                $this->printHeader($lang['strtables'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
87
            } elseif ('view' == $_REQUEST['subject']) {
88
                $this->printHeader($lang['strviews'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
89
            } elseif ('matview' == $_REQUEST['subject']) {
90
                $this->printHeader('M' . $lang['strviews'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
91
            } elseif ('column' == $_REQUEST['subject']) {
92
                $this->printHeader($lang['strcolumn'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
93
            }
94
        } else {
95
            $this->printHeader($lang['strqueryresults'], $scripts, true, $header_template);
96
        }
97
98
        $this->printBody();
99
100
        echo $output;
101
102
        $this->printFooter(true, $footer_template);
103
    }
104
105
    /**
106
     * Displays requested data.
107
     *
108
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
109
     */
110
    public function doBrowse($msg = '')
111
    {
112
        $conf           = $this->conf;
113
        $this->misc     = $this->misc;
114
        $lang           = $this->lang;
115
        $plugin_manager = $this->plugin_manager;
116
        $data           = $this->misc->getDatabaseAccessor();
117
118
        $save_history = false;
119
        // If current page is not set, default to first page
120
        if (!isset($_REQUEST['page'])) {
121
            $_REQUEST['page'] = 1;
122
        }
123
124
        if (!isset($_REQUEST['nohistory'])) {
125
            $save_history = true;
126
        }
127
128
        if (isset($_REQUEST['subject'])) {
129
            $subject = $_REQUEST['subject'];
130
            if (isset($_REQUEST[$subject])) {
131
                $object = $_REQUEST[$subject];
132
            }
133
        } else {
134
            $subject = '';
135
        }
136
137
        $this->printTrail(isset($subject) ? $subject : 'database');
138
        $this->printTabs($subject, 'browse');
139
140
        // This code is used when browsing FK in pure-xHTML (without js)
141
        if (isset($_REQUEST['fkey'])) {
142
            $ops = [];
143
            foreach ($_REQUEST['fkey'] as $x => $y) {
144
                $ops[$x] = '=';
145
            }
146
            $query             = $data->getSelectSQL($_REQUEST['table'], [], $_REQUEST['fkey'], $ops);
147
            $_REQUEST['query'] = $query;
148
        }
149
150
        if (isset($object)) {
151
            if (isset($_REQUEST['query'])) {
152
                $_SESSION['sqlquery'] = $_REQUEST['query'];
153
                $this->printTitle($lang['strselect']);
154
                $type = 'SELECT';
155
            } else {
156
                $type = 'TABLE';
157
            }
158
        } else {
159
            $this->printTitle($lang['strqueryresults']);
160
            // we comes from sql.php, $_SESSION['sqlquery'] has been set there
161
            $type = 'QUERY';
162
        }
163
164
        $this->printMsg($msg);
165
166
        // If 'sortkey' is not set, default to ''
167
        if (!isset($_REQUEST['sortkey'])) {
168
            $_REQUEST['sortkey'] = '';
169
        }
170
171
        // If 'sortdir' is not set, default to ''
172
        if (!isset($_REQUEST['sortdir'])) {
173
            $_REQUEST['sortdir'] = '';
174
        }
175
176
        // If 'strings' is not set, default to collapsed
177
        if (!isset($_REQUEST['strings'])) {
178
            $_REQUEST['strings'] = 'collapsed';
179
        }
180
181
        // Fetch unique row identifier, if this is a table browse request.
182
        if (isset($object)) {
183
            $key = $data->getRowIdentifier($object);
184
        } else {
185
            $key = [];
186
        }
187
188
        // Set the schema search path
189
        if (isset($_REQUEST['search_path'])) {
190
            if (0 != $data->setSearchPath(array_map('trim', explode(',', $_REQUEST['search_path'])))) {
191
                return;
192
            }
193
        }
194
195
        try {
196
            // Retrieve page from query.  $max_pages is returned by reference.
197
            $resultset = $data->browseQuery(
198
                $type,
199
                isset($object) ? $object : null,
200
                isset($_SESSION['sqlquery']) ? $_SESSION['sqlquery'] : null,
201
                $_REQUEST['sortkey'],
202
                $_REQUEST['sortdir'],
203
                $_REQUEST['page'],
204
                $this->conf['max_rows'],
205
                $max_pages
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $max_pages seems to be never defined.
Loading history...
206
            );
207
        } catch (\PHPPgAdmin\ADOdbException $e) {
208
            return;
209
        }
210
211
        $fkey_information = $this->getFKInfo();
212
213
        // Build strings for GETs in array
214
        $_gets = [
215
            'server'   => $_REQUEST['server'],
216
            'database' => $_REQUEST['database'],
217
        ];
218
219
        if (isset($_REQUEST['schema'])) {
220
            $_gets['schema'] = $_REQUEST['schema'];
221
        }
222
223
        if (isset($object)) {
224
            $_gets[$subject] = $object;
225
        }
226
227
        if (isset($subject)) {
228
            $_gets['subject'] = $subject;
229
        }
230
231
        if (isset($_REQUEST['query'])) {
232
            $_gets['query'] = $_REQUEST['query'];
233
        }
234
235
        if (isset($_REQUEST['count'])) {
236
            $_gets['count'] = $_REQUEST['count'];
237
        }
238
239
        if (isset($_REQUEST['return'])) {
240
            $_gets['return'] = $_REQUEST['return'];
241
        }
242
243
        if (isset($_REQUEST['search_path'])) {
244
            $_gets['search_path'] = $_REQUEST['search_path'];
245
        }
246
247
        if (isset($_REQUEST['table'])) {
248
            $_gets['table'] = $_REQUEST['table'];
249
        }
250
251
        if (isset($_REQUEST['sortkey'])) {
252
            $_gets['sortkey'] = $_REQUEST['sortkey'];
253
        }
254
255
        if (isset($_REQUEST['sortdir'])) {
256
            $_gets['sortdir'] = $_REQUEST['sortdir'];
257
        }
258
259
        if (isset($_REQUEST['nohistory'])) {
260
            $_gets['nohistory'] = $_REQUEST['nohistory'];
261
        }
262
263
        $_gets['strings'] = $_REQUEST['strings'];
264
265
        if ($save_history && is_object($resultset) && ('QUERY' == $type)) {
266
            //{
267
            $this->misc->saveScriptHistory($_REQUEST['query']);
268
        }
269
270
        if (isset($_REQUEST['query'])) {
271
            $query = $_REQUEST['query'];
272
        } else {
273
            $query = "SELECT * FROM {$_REQUEST['schema']}";
274
            if ('matview' == $_REQUEST['subject']) {
275
                $query = "{$query}.{$_REQUEST['matview']};";
276
            } elseif ('view' == $_REQUEST['subject']) {
277
                $query = "{$query}.{$_REQUEST['view']};";
278
            } else {
279
                $query = "{$query}.{$_REQUEST['table']};";
280
            }
281
        }
282
        //$query = isset($_REQUEST['query'])? $_REQUEST['query'] : "select * from {$_REQUEST['schema']}.{$_REQUEST['table']};";
283
        $this->prtrace($query);
284
        //die(htmlspecialchars($query));
285
286
        echo '<form method="post" id="sqlform" action="' . $_SERVER['REQUEST_URI'] . '">';
287
        echo '<textarea width="90%" name="query"  id="query" rows="5" cols="100" resizable="true">';
288
289
        echo htmlspecialchars($query);
290
        echo '</textarea><br><input type="submit"/></form>';
291
292
        if (is_object($resultset) && $resultset->recordCount() > 0) {
293
            // Show page navigation
294
            $this->misc->printPages($_REQUEST['page'], $max_pages, $_gets);
295
296
            echo "<table id=\"data\">\n<tr>";
297
298
            // Check that the key is actually in the result set.  This can occur for select
299
            // operations where the key fields aren't part of the select.  XXX:  We should
300
            // be able to support this, somehow.
301
            foreach ($key as $v) {
302
                // If a key column is not found in the record set, then we
303
                // can't use the key.
304
                if (!in_array($v, array_keys($resultset->fields), true)) {
305
                    $key = [];
306
307
                    break;
308
                }
309
            }
310
311
            $buttons = [
312
                'edit'   => [
313
                    'content' => $lang['stredit'],
314
                    'attr'    => [
315
                        'href' => [
316
                            'url'     => 'display.php',
317
                            'urlvars' => array_merge([
1 ignored issue
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
318
                                'action'  => 'confeditrow',
319
                                'strings' => $_REQUEST['strings'],
320
                                'page'    => $_REQUEST['page'],
321
                            ], $_gets),
1 ignored issue
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
322
                        ],
323
                    ],
324
                ],
325
                'delete' => [
326
                    'content' => $lang['strdelete'],
327
                    'attr'    => [
328
                        'href' => [
329
                            'url'     => 'display.php',
330
                            'urlvars' => array_merge([
1 ignored issue
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
331
                                'action'  => 'confdelrow',
332
                                'strings' => $_REQUEST['strings'],
333
                                'page'    => $_REQUEST['page'],
334
                            ], $_gets),
1 ignored issue
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
335
                        ],
336
                    ],
337
                ],
338
            ];
339
            $actions = [
340
                'actionbuttons' => &$buttons,
341
                'place'         => 'display-browse',
342
            ];
343
            $plugin_manager->do_hook('actionbuttons', $actions);
344
345
            foreach (array_keys($actions['actionbuttons']) as $action) {
346
                $actions['actionbuttons'][$action]['attr']['href']['urlvars'] = array_merge(
347
                    $actions['actionbuttons'][$action]['attr']['href']['urlvars'],
348
                    $_gets
349
                );
350
            }
351
352
            $edit_params = isset($actions['actionbuttons']['edit']) ?
353
            $actions['actionbuttons']['edit'] : [];
354
            $delete_params = isset($actions['actionbuttons']['delete']) ?
355
            $actions['actionbuttons']['delete'] : [];
356
357
            // Display edit and delete actions if we have a key
358
            $colspan = count($buttons);
359
            if ($colspan > 0 and count($key) > 0) {
360
                echo "<th colspan=\"{$colspan}\" class=\"data\">{$lang['stractions']}</th>" . "\n";
361
            }
362
363
            // we show OIDs only if we are in TABLE or SELECT type browsing
364
            $this->printTableHeaderCells($resultset, $_gets, isset($object));
365
366
            echo '</tr>' . "\n";
367
368
            $i = 0;
369
            reset($resultset->fields);
370
            while (!$resultset->EOF) {
371
                $id = (0 == ($i % 2) ? '1' : '2');
372
                echo "<tr class=\"data{$id}\">" . "\n";
373
                // Display edit and delete links if we have a key
374
                if ($colspan > 0 and count($key) > 0) {
375
                    $keys_array = [];
376
                    $has_nulls  = false;
377
                    foreach ($key as $v) {
378
                        if (null === $resultset->fields[$v]) {
379
                            $has_nulls = true;
380
381
                            break;
382
                        }
383
                        $keys_array["key[{$v}]"] = $resultset->fields[$v];
384
                    }
385
                    if ($has_nulls) {
386
                        echo "<td colspan=\"{$colspan}\">&nbsp;</td>" . "\n";
387
                    } else {
388
                        if (isset($actions['actionbuttons']['edit'])) {
389
                            $actions['actionbuttons']['edit']                            = $edit_params;
390
                            $actions['actionbuttons']['edit']['attr']['href']['urlvars'] = array_merge(
391
                                $actions['actionbuttons']['edit']['attr']['href']['urlvars'],
392
                                $keys_array
393
                            );
394
                        }
395
396
                        if (isset($actions['actionbuttons']['delete'])) {
397
                            $actions['actionbuttons']['delete']                            = $delete_params;
398
                            $actions['actionbuttons']['delete']['attr']['href']['urlvars'] = array_merge(
399
                                $actions['actionbuttons']['delete']['attr']['href']['urlvars'],
400
                                $keys_array
401
                            );
402
                        }
403
404
                        foreach ($actions['actionbuttons'] as $action) {
405
                            echo "<td class=\"opbutton{$id}\">";
406
                            $this->printLink($action, true, __METHOD__);
407
                            echo '</td>' . "\n";
408
                        }
409
                    }
410
                }
411
412
                $this->printTableRowCells($resultset, $fkey_information, isset($object));
413
414
                echo '</tr>' . "\n";
415
                $resultset->moveNext();
416
                ++$i;
417
            }
418
            echo '</table>' . "\n";
419
420
            echo '<p>', $resultset->recordCount(), " {$lang['strrows']}</p>" . "\n";
421
            // Show page navigation
422
            $this->misc->printPages($_REQUEST['page'], $max_pages, $_gets);
423
        } else {
424
            echo "<p>{$lang['strnodata']}</p>" . "\n";
425
        }
426
427
        // Navigation links
428
        $navlinks = [];
429
430
        $fields = [
431
            'server'   => $_REQUEST['server'],
432
            'database' => $_REQUEST['database'],
433
        ];
434
435
        if (isset($_REQUEST['schema'])) {
436
            $fields['schema'] = $_REQUEST['schema'];
437
        }
438
439
        // Return
440
        if (isset($_REQUEST['return'])) {
441
            $urlvars = $this->misc->getSubjectParams($_REQUEST['return']);
442
443
            $navlinks['back'] = [
444
                'attr'    => [
445
                    'href' => [
446
                        'url'     => $urlvars['url'],
447
                        'urlvars' => $urlvars['params'],
448
                    ],
449
                ],
450
                'content' => $lang['strback'],
451
            ];
452
        }
453
454
        // Edit SQL link
455
        if ('QUERY' == $type) {
456
            $navlinks['edit'] = [
457
                'attr'    => [
458
                    'href' => [
459
                        'url'     => 'database.php',
460
                        'urlvars' => array_merge($fields, [
1 ignored issue
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
461
                            'action'   => 'sql',
462
                            'paginate' => 'on',
463
                        ]),
1 ignored issue
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
464
                    ],
465
                ],
466
                'content' => $lang['streditsql'],
467
            ];
468
        }
469
470
        // Expand/Collapse
471
        if ('expanded' == $_REQUEST['strings']) {
472
            $navlinks['collapse'] = [
473
                'attr'    => [
474
                    'href' => [
475
                        'url'     => 'display.php',
476
                        'urlvars' => array_merge(
477
                            $_gets,
478
                            [
479
                                'strings' => 'collapsed',
480
                                'page'    => $_REQUEST['page'],
481
                            ]
482
                        ),
483
                    ],
484
                ],
485
                'content' => $lang['strcollapse'],
486
            ];
487
        } else {
488
            $navlinks['collapse'] = [
489
                'attr'    => [
490
                    'href' => [
491
                        'url'     => 'display.php',
492
                        'urlvars' => array_merge(
493
                            $_gets,
494
                            [
495
                                'strings' => 'expanded',
496
                                'page'    => $_REQUEST['page'],
497
                            ]
498
                        ),
499
                    ],
500
                ],
501
                'content' => $lang['strexpand'],
502
            ];
503
        }
504
505
        // Create view and download
506
        if (isset($_REQUEST['query'], $resultset) && is_object($resultset) && $resultset->recordCount() > 0) {
507
            // Report views don't set a schema, so we need to disable create view in that case
508
            if (isset($_REQUEST['schema'])) {
509
                $navlinks['createview'] = [
510
                    'attr'    => [
511
                        'href' => [
512
                            'url'     => 'views.php',
513
                            'urlvars' => array_merge($fields, [
1 ignored issue
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
514
                                'action'         => 'create',
515
                                'formDefinition' => $_REQUEST['query'],
516
                            ]),
1 ignored issue
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
517
                        ],
518
                    ],
519
                    'content' => $lang['strcreateview'],
520
                ];
521
            }
522
523
            $urlvars = [];
524
            if (isset($_REQUEST['search_path'])) {
525
                $urlvars['search_path'] = $_REQUEST['search_path'];
526
            }
527
528
            $navlinks['download'] = [
529
                'attr'    => [
530
                    'href' => [
531
                        'url'     => 'dataexport.php',
532
                        'urlvars' => array_merge($fields, $urlvars),
533
                    ],
534
                ],
535
                'content' => $lang['strdownload'],
536
            ];
537
        }
538
539
        // Insert
540
        if (isset($object) && (isset($subject) && 'table' == $subject)) {
541
            $navlinks['insert'] = [
542
                'attr'    => [
543
                    'href' => [
544
                        'url'     => 'tables.php',
545
                        'urlvars' => array_merge($fields, [
1 ignored issue
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
546
                            'action' => 'confinsertrow',
547
                            'table'  => $object,
548
                        ]),
1 ignored issue
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
549
                    ],
550
                ],
551
                'content' => $lang['strinsert'],
552
            ];
553
        }
554
555
        // Refresh
556
        $navlinks['refresh'] = [
557
            'attr'    => [
558
                'href' => [
559
                    'url'     => 'display.php',
560
                    'urlvars' => array_merge(
561
                        $_gets,
562
                        [
563
                            'strings' => $_REQUEST['strings'],
564
                            'page'    => $_REQUEST['page'],
565
                        ]
566
                    ),
567
                ],
568
            ],
569
            'content' => $lang['strrefresh'],
570
        ];
571
572
        $this->printNavLinks($navlinks, 'display-browse', get_defined_vars());
573
    }
574
575
    /**
576
     * Show confirmation of edit and perform actual update.
577
     *
578
     * @param mixed $confirm
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
579
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
580
     */
581
    public function doEditRow($confirm, $msg = '')
582
    {
583
        $lang = $this->lang;
584
        $data = $this->misc->getDatabaseAccessor();
585
586
        if (is_array($_REQUEST['key'])) {
587
            $key = $_REQUEST['key'];
588
        } else {
589
            $key = unserialize(urldecode($_REQUEST['key']));
590
        }
591
592
        if ($confirm) {
593
            $this->printTrail($_REQUEST['subject']);
594
            $this->printTitle($lang['streditrow']);
595
            $this->printMsg($msg);
596
597
            $attrs     = $data->getTableAttributes($_REQUEST['table']);
598
            $resultset = $data->browseRow($_REQUEST['table'], $key);
599
600
            if (('disable' != $this->conf['autocomplete'])) {
601
                $fksprops = $this->misc->getAutocompleteFKProperties($_REQUEST['table']);
602
                if (false !== $fksprops) {
603
                    echo $fksprops['code'];
604
                }
605
            } else {
606
                $fksprops = false;
607
            }
608
609
            echo '<form action="' . \SUBFOLDER . '/src/views/display.php" method="post" id="ac_form">' . "\n";
610
611
            /*echo '<p>';
612
            if (!$error) {
613
            echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$lang['strsave']}\" />" . "\n";
614
            }
615
616
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
617
618
            echo '</p>' . "\n";*/
619
620
            $elements = 0;
621
            $error    = true;
622
            if (1 == $resultset->recordCount() && $attrs->recordCount() > 0) {
623
                echo '<table>' . "\n";
624
625
                // Output table header
626
                echo "<tr><th class=\"data\">{$lang['strcolumn']}</th><th class=\"data\">{$lang['strtype']}</th>";
627
                echo "<th class=\"data\">{$lang['strformat']}</th>" . "\n";
628
                echo "<th class=\"data\">{$lang['strnull']}</th><th class=\"data\">{$lang['strvalue']}</th></tr>";
629
630
                $i = 0;
631
                while (!$attrs->EOF) {
632
                    $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']);
633
                    $id                          = (0 == ($i % 2) ? '1' : '2');
634
635
                    // Initialise variables
636
                    if (!isset($_REQUEST['format'][$attrs->fields['attname']])) {
637
                        $_REQUEST['format'][$attrs->fields['attname']] = 'VALUE';
638
                    }
639
640
                    echo "<tr class=\"data{$id}\">" . "\n";
641
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($attrs->fields['attname']), '</td>';
642
                    echo '<td style="white-space:nowrap;">' . "\n";
643
                    echo $this->misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod']));
644
                    echo '<input type="hidden" name="types[', htmlspecialchars($attrs->fields['attname']), ']" value="',
645
                    htmlspecialchars($attrs->fields['type']), '" /></td>';
646
                    ++$elements;
647
                    echo '<td style="white-space:nowrap;">' . "\n";
648
                    echo '<select name="format[' . htmlspecialchars($attrs->fields['attname']), ']">' . "\n";
649
                    echo '<option value="VALUE"', ($_REQUEST['format'][$attrs->fields['attname']] == 'VALUE') ? ' selected="selected"' : '', ">{$lang['strvalue']}</option>" . "\n";
650
                    $selected = ($_REQUEST['format'][$attrs->fields['attname']] == 'EXPRESSION') ? ' selected="selected"' : '';
651
                    echo '<option value="EXPRESSION"' . $selected . ">{$lang['strexpression']}</option>" . "\n";
652
                    echo "</select>\n</td>" . "\n";
653
                    ++$elements;
654
                    echo '<td style="white-space:nowrap;">';
655
                    // Output null box if the column allows nulls (doesn't look at CHECKs or ASSERTIONS)
656
                    if (!$attrs->fields['attnotnull']) {
657
                        // Set initial null values
658
                        if ('confeditrow' == $_REQUEST['action'] && null === $resultset->fields[$attrs->fields['attname']]) {
659
                            $_REQUEST['nulls'][$attrs->fields['attname']] = 'on';
660
                        }
661
                        echo "<label><span><input type=\"checkbox\" name=\"nulls[{$attrs->fields['attname']}]\"",
662
                        isset($_REQUEST['nulls'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></span></label></td>' . "\n";
663
                        ++$elements;
664
                    } else {
665
                        echo '&nbsp;</td>';
666
                    }
667
668
                    echo "<td id=\"row_att_{$attrs->fields['attnum']}\" style=\"white-space:nowrap;\">";
669
670
                    $extras = [];
671
672
                    // If the column allows nulls, then we put a JavaScript action on the data field to unset the
673
                    // NULL checkbox as soon as anything is entered in the field.  We use the $elements variable to
674
                    // keep track of which element offset we're up to.  We can't refer to the null checkbox by name
675
                    // as it contains '[' and ']' characters.
676
                    if (!$attrs->fields['attnotnull']) {
677
                        $extras['onChange'] = 'elements[' . ($elements - 1) . '].checked = false;';
678
                    }
679
680
                    if ((false !== $fksprops) && isset($fksprops['byfield'][$attrs->fields['attnum']])) {
681
                        $extras['id']           = "attr_{$attrs->fields['attnum']}";
682
                        $extras['autocomplete'] = 'off';
683
                    }
684
685
                    echo $data->printField("values[{$attrs->fields['attname']}]", $resultset->fields[$attrs->fields['attname']], $attrs->fields['type'], $extras);
686
687
                    echo '</td>';
688
                    ++$elements;
689
                    echo '</tr>' . "\n";
690
                    ++$i;
691
                    $attrs->moveNext();
692
                }
693
                echo '</table>' . "\n";
694
695
                $error = false;
696
            } elseif (1 != $resultset->recordCount()) {
697
                echo "<p>{$lang['strrownotunique']}</p>" . "\n";
698
            } else {
699
                echo "<p>{$lang['strinvalidparam']}</p>" . "\n";
700
            }
701
702
            echo '<input type="hidden" name="action" value="editrow" />' . "\n";
703
            echo $this->misc->form;
704
            if (isset($_REQUEST['table'])) {
705
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />' . "\n";
706
            }
707
708
            if (isset($_REQUEST['subject'])) {
709
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />' . "\n";
710
            }
711
712
            if (isset($_REQUEST['query'])) {
713
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />' . "\n";
714
            }
715
716
            if (isset($_REQUEST['count'])) {
717
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />' . "\n";
718
            }
719
720
            if (isset($_REQUEST['return'])) {
721
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />' . "\n";
722
            }
723
724
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />' . "\n";
725
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />' . "\n";
726
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />' . "\n";
727
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />' . "\n";
728
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($key))), '" />' . "\n";
729
            echo '<p>';
730
            if (!$error) {
731
                echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$lang['strsave']}\" />" . "\n";
732
            }
733
734
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
735
736
            if (false !== $fksprops) {
737
                if ('default off' != $this->conf['autocomplete']) {
738
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"1\" checked=\"checked\" /><label for=\"no_ac\">{$lang['strac']}</label>" . "\n";
739
                } else {
740
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"0\" /><label for=\"no_ac\">{$lang['strac']}</label>" . "\n";
741
                }
742
            }
743
744
            echo '</p>' . "\n";
745
            echo '</form>' . "\n";
746
        } else {
747
            if (!isset($_POST['values'])) {
748
                $_POST['values'] = [];
749
            }
750
751
            if (!isset($_POST['nulls'])) {
752
                $_POST['nulls'] = [];
753
            }
754
755
            $status = $data->editRow(
756
                $_POST['table'],
757
                $_POST['values'],
758
                $_POST['nulls'],
759
                $_POST['format'],
760
                $_POST['types'],
761
                $key
762
            );
763
            if (0 == $status) {
764
                $this->doBrowse($lang['strrowupdated']);
765
            } elseif ($status == -2) {
766
                $this->doEditRow(true, $lang['strrownotunique']);
767
            } else {
768
                $this->doEditRow(true, $lang['strrowupdatedbad']);
769
            }
770
        }
771
    }
772
773
    /**
774
     * Show confirmation of drop and perform actual drop.
775
     *
776
     * @param mixed $confirm
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
777
     */
778
    public function doDelRow($confirm)
779
    {
780
        $lang = $this->lang;
781
        $data = $this->misc->getDatabaseAccessor();
782
783
        if ($confirm) {
784
            $this->printTrail($_REQUEST['subject']);
785
            $this->printTitle($lang['strdeleterow']);
786
787
            $resultset = $data->browseRow($_REQUEST['table'], $_REQUEST['key']);
788
789
            echo '<form action="' . \SUBFOLDER . '/src/views/display.php" method="post">' . "\n";
790
            echo $this->misc->form;
791
792
            if (1 == $resultset->recordCount()) {
793
                echo "<p>{$lang['strconfdeleterow']}</p>" . "\n";
794
795
                $fkinfo = [];
796
                echo '<table><tr>';
797
                $this->printTableHeaderCells($resultset, false, true);
798
                echo '</tr>';
799
                echo '<tr class="data1">' . "\n";
800
                $this->printTableRowCells($resultset, $fkinfo, true);
801
                echo '</tr>' . "\n";
802
                echo '</table>' . "\n";
803
                echo '<br />' . "\n";
804
805
                echo '<input type="hidden" name="action" value="delrow" />' . "\n";
806
                echo "<input type=\"submit\" name=\"yes\" value=\"{$lang['stryes']}\" />" . "\n";
807
                echo "<input type=\"submit\" name=\"no\" value=\"{$lang['strno']}\" />" . "\n";
808
            } elseif (1 != $resultset->recordCount()) {
809
                echo "<p>{$lang['strrownotunique']}</p>" . "\n";
810
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
811
            } else {
812
                echo "<p>{$lang['strinvalidparam']}</p>" . "\n";
813
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
814
            }
815
            if (isset($_REQUEST['table'])) {
816
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />' . "\n";
817
            }
818
819
            if (isset($_REQUEST['subject'])) {
820
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />' . "\n";
821
            }
822
823
            if (isset($_REQUEST['query'])) {
824
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />' . "\n";
825
            }
826
827
            if (isset($_REQUEST['count'])) {
828
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />' . "\n";
829
            }
830
831
            if (isset($_REQUEST['return'])) {
832
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />' . "\n";
833
            }
834
835
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />' . "\n";
836
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />' . "\n";
837
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />' . "\n";
838
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />' . "\n";
839
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($_REQUEST['key']))), '" />' . "\n";
840
            echo '</form>' . "\n";
841
        } else {
842
            $status = $data->deleteRow($_POST['table'], unserialize(urldecode($_POST['key'])));
843
            if (0 == $status) {
844
                $this->doBrowse($lang['strrowdeleted']);
845
            } elseif ($status == -2) {
846
                $this->doBrowse($lang['strrownotunique']);
847
            } else {
848
                $this->doBrowse($lang['strrowdeletedbad']);
849
            }
850
        }
851
    }
852
853
    /**
854
     * build & return the FK information data structure
1 ignored issue
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
855
     * used when deciding if a field should have a FK link or not.
856
     *
857
     * @return [type] [description]
858
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
859
    public function &getFKInfo()
860
    {
861
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
862
        $data = $this->misc->getDatabaseAccessor();
863
864
        // Get the foreign key(s) information from the current table
865
        $fkey_information = ['byconstr' => [], 'byfield' => []];
866
867
        if (isset($_REQUEST['table'])) {
868
            $constraints = $data->getConstraintsWithFields($_REQUEST['table']);
869
            if ($constraints->recordCount() > 0) {
870
                $fkey_information['common_url'] = $this->misc->getHREF('schema') . '&amp;subject=table';
871
872
                // build the FK constraints data structure
873
                while (!$constraints->EOF) {
874
                    $constr = &$constraints->fields;
875
                    if ('f' == $constr['contype']) {
876
                        if (!isset($fkey_information['byconstr'][$constr['conid']])) {
877
                            $fkey_information['byconstr'][$constr['conid']] = [
878
                                'url_data' => 'table=' . urlencode($constr['f_table']) . '&amp;schema=' . urlencode($constr['f_schema']),
879
                                'fkeys'    => [],
880
                                'consrc'   => $constr['consrc'],
881
                            ];
882
                        }
883
884
                        $fkey_information['byconstr'][$constr['conid']]['fkeys'][$constr['p_field']] = $constr['f_field'];
885
886
                        if (!isset($fkey_information['byfield'][$constr['p_field']])) {
887
                            $fkey_information['byfield'][$constr['p_field']] = [];
888
                        }
889
890
                        $fkey_information['byfield'][$constr['p_field']][] = $constr['conid'];
891
                    }
892
                    $constraints->moveNext();
893
                }
894
            }
895
        }
896
897
        return $fkey_information;
898
    }
899
900
    /**
901
     * Print table header cells.
902
     *
903
     * @param $args - associative array for sort link parameters
904
     * @param mixed $withOid
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Doc comment for parameter $withOid does not match actual variable name $args
Loading history...
905
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment - at position 0 could not be parsed: Unknown type name '-' at position 0 in -.
Loading history...
906
    public function printTableHeaderCells(&$resultset, $args, $withOid)
907
    {
908
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
909
        $data = $this->misc->getDatabaseAccessor();
910
        $j    = 0;
911
912
        foreach ($resultset->fields as $k => $v) {
913
            if (($k === $data->id) && (!($withOid && $this->conf['show_oids']))) {
914
                ++$j;
915
916
                continue;
917
            }
918
            $finfo = $resultset->fetchField($j);
919
920
            if (false === $args) {
921
                echo '<th class="data">', $this->misc->printVal($finfo->name), '</th>' . "\n";
922
            } else {
923
                $args['page']    = $_REQUEST['page'];
924
                $args['sortkey'] = $j + 1;
925
                // Sort direction opposite to current direction, unless it's currently ''
926
                $args['sortdir'] = (
927
                    'asc' == $_REQUEST['sortdir']
928
                    and $_REQUEST['sortkey'] == ($j + 1)
929
                ) ? 'desc' : 'asc';
930
931
                $sortLink = http_build_query($args);
932
933
                echo "<th class=\"data\"><a href=\"?{$sortLink}\">"
934
                , $this->misc->printVal($finfo->name);
935
                if ($_REQUEST['sortkey'] == ($j + 1)) {
936
                    if ('asc' == $_REQUEST['sortdir']) {
937
                        echo '<img src="' . $this->misc->icon('RaiseArgument') . '" alt="asc">';
938
                    } else {
939
                        echo '<img src="' . $this->misc->icon('LowerArgument') . '" alt="desc">';
940
                    }
941
                }
942
                echo '</a></th>' . "\n";
943
            }
944
            ++$j;
945
        }
946
947
        reset($resultset->fields);
948
    }
949
950
    // Print data-row cells
951
    public function printTableRowCells(&$resultset, &$fkey_information, $withOid)
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
952
    {
953
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
954
        $data = $this->misc->getDatabaseAccessor();
955
        $j    = 0;
956
957
        if (!isset($_REQUEST['strings'])) {
958
            $_REQUEST['strings'] = 'collapsed';
959
        }
960
961
        foreach ($resultset->fields as $k => $v) {
962
            $finfo = $resultset->fetchField($j++);
963
964
            if (($k === $data->id) && (!($withOid && $this->conf['show_oids']))) {
965
                continue;
966
            }
967
            if (null !== $v && '' == $v) {
968
                echo '<td>&nbsp;</td>';
969
            } else {
970
                echo '<td style="white-space:nowrap;">';
971
972
                if ((null !== $v) && isset($fkey_information['byfield'][$k])) {
973
                    foreach ($fkey_information['byfield'][$k] as $conid) {
974
                        $query_params = $fkey_information['byconstr'][$conid]['url_data'];
975
976
                        foreach ($fkey_information['byconstr'][$conid]['fkeys'] as $p_field => $f_field) {
977
                            $query_params .= '&amp;' . urlencode("fkey[{$f_field}]") . '=' . urlencode($resultset->fields[$p_field]);
978
                        }
979
980
                        // $fkey_information['common_url'] is already urlencoded
981
                        $query_params .= '&amp;' . $fkey_information['common_url'];
982
                        echo '<div style="display:inline-block;">';
983
                        echo '<a class="fk fk_' . htmlentities($conid, ENT_QUOTES, 'UTF-8') . "\" href=\"display.php?{$query_params}\">";
984
                        echo '<img src="' . $this->misc->icon('ForeignKey') . '" style="vertical-align:middle;" alt="[fk]" title="'
985
                        . htmlentities($fkey_information['byconstr'][$conid]['consrc'], ENT_QUOTES, 'UTF-8')
986
                            . '" />';
987
                        echo '</a>';
988
                        echo '</div>';
989
                    }
990
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings']), 'class' => 'fk_value']);
991
                } else {
992
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings'])]);
993
                }
994
                echo '</td>';
995
            }
996
        }
997
    }
998
999
    // Print the FK row, used in ajax requests
1000
    public function doBrowseFK()
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
1001
    {
1002
        $lang = $this->lang;
1003
        $data = $this->misc->getDatabaseAccessor();
1004
1005
        $ops = [];
1006
        foreach ($_REQUEST['fkey'] as $x => $y) {
1007
            $ops[$x] = '=';
1008
        }
1009
        $query             = $data->getSelectSQL($_REQUEST['table'], [], $_REQUEST['fkey'], $ops);
1010
        $_REQUEST['query'] = $query;
1011
1012
        $fkinfo = $this->getFKInfo();
1013
1014
        $max_pages = 1;
1015
        // Retrieve page from query.  $max_pages is returned by reference.
1016
        $resultset = $data->browseQuery(
1017
            'SELECT',
1018
            $_REQUEST['table'],
1019
            $_REQUEST['query'],
1020
            null,
1021
            null,
1022
            1,
1023
            1,
1024
            $max_pages
1025
        );
1026
1027
        echo '<a href="javascript:void(0);" style="display:table-cell;" class="fk_delete"><img alt="[delete]" src="' . $this->misc->icon('Delete') . '" /></a>' . "\n";
1028
        echo '<div style="display:table-cell;">';
1029
1030
        if (is_object($resultset) && $resultset->recordCount() > 0) {
1031
            /* we are browsing a referenced table here
1032
             * we should show OID if show_oids is true
1033
             * so we give true to withOid in functions bellow
1034
             */
1035
            echo '<table><tr>';
1036
            $this->printTableHeaderCells($resultset, false, true);
1037
            echo '</tr>';
1038
            echo '<tr class="data1">' . "\n";
1039
            $this->printTableRowCells($resultset, $fkinfo, true);
1040
            echo '</tr>' . "\n";
1041
            echo '</table>' . "\n";
1042
        } else {
1043
            echo $lang['strnodata'];
1044
        }
1045
        echo '</div>';
1046
    }
1047
}
1048