Passed
Pull Request — develop (#92)
by Felipe
04:47
created

src/controllers/DisplayController.php (11 issues)

1
<?php
2
0 ignored issues
show
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
 */
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;
22
        $this->misc     = $this->misc;
23
        $lang           = $this->lang;
24
        $plugin_manager = $this->plugin_manager;
25
        $data           = $this->misc->getDatabaseAccessor();
26
        $action         = $this->action;
27
28
        if ('dobrowsefk' == $action) {
29
            return $this->doBrowseFK();
30
        }
31
32
        set_time_limit(0);
33
34
        $scripts = '<script src="'.\SUBFOLDER.'/js/display.js" type="text/javascript"></script>';
35
36
        $scripts .= '<script type="text/javascript">'."\n";
37
        $scripts .= "var Display = {\n";
38
        $scripts .= "errmsg: '".str_replace("'", "\\'", $lang['strconnectionfail'])."'\n";
39
        $scripts .= "};\n";
40
        $scripts .= '</script>'."\n";
41
42
        $footer_template = 'footer.twig';
43
        $header_template = 'header.twig';
44
45
        ob_start();
46
        switch ($action) {
47
            case 'editrow':
48
                $header_template = 'header_sqledit.twig';
49
                $footer_template = 'footer_sqledit.twig';
50
                if (isset($_POST['save'])) {
51
                    $this->doEditRow(false);
52
                } else {
53
                    $this->doBrowse();
54
                }
55
56
                break;
57
            case 'confeditrow':
58
                $this->doEditRow(true);
59
60
                break;
61
            case 'delrow':
62
                $header_template = 'header_sqledit.twig';
63
                $footer_template = 'footer_sqledit.twig';
64
                if (isset($_POST['yes'])) {
65
                    $this->doDelRow(false);
66
                } else {
67
                    $this->doBrowse();
68
                }
69
70
                break;
71
            case 'confdelrow':
72
                $this->doDelRow(true);
73
74
                break;
75
            default:
76
                $header_template = 'header_sqledit.twig';
77
                $footer_template = 'footer_sqledit.twig';
78
                $this->doBrowse();
79
80
                break;
81
        }
82
        $output = ob_get_clean();
83
84
        // Set the title based on the subject of the request
85
        if (isset($_REQUEST['subject'], $_REQUEST[$_REQUEST['subject']])) {
86
            if ('table' == $_REQUEST['subject']) {
87
                $this->printHeader($lang['strtables'].': '.$_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
88
            } elseif ('view' == $_REQUEST['subject']) {
89
                $this->printHeader($lang['strviews'].': '.$_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
90
            } elseif ('matview' == $_REQUEST['subject']) {
91
                $this->printHeader('M'.$lang['strviews'].': '.$_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
92
            } elseif ('column' == $_REQUEST['subject']) {
93
                $this->printHeader($lang['strcolumn'].': '.$_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
94
            }
95
        } else {
96
            $this->printHeader($lang['strqueryresults'], $scripts, true, $header_template);
97
        }
98
99
        $this->printBody();
100
101
        echo $output;
102
103
        $this->printFooter(true, $footer_template);
104
    }
105
106
    /**
107
     * Displays requested data.
108
     *
109
     * @param mixed $msg
1 ignored issue
show
Missing parameter comment
Loading history...
110
     */
111
    public function doBrowse($msg = '')
112
    {
113
        $conf           = $this->conf;
114
        $this->misc     = $this->misc;
115
        $lang           = $this->lang;
116
        $plugin_manager = $this->plugin_manager;
117
        $data           = $this->misc->getDatabaseAccessor();
118
119
        $save_history = false;
120
        // If current page is not set, default to first page
121
        if (!isset($_REQUEST['page'])) {
122
            $_REQUEST['page'] = 1;
123
        }
124
125
        if (!isset($_REQUEST['nohistory'])) {
126
            $save_history = true;
127
        }
128
129
        if (isset($_REQUEST['subject'])) {
130
            $subject = $_REQUEST['subject'];
131
            if (isset($_REQUEST[$subject])) {
132
                $object = $_REQUEST[$subject];
133
            }
134
        } else {
135
            $subject = '';
136
        }
137
138
        $this->printTrail(isset($subject) ? $subject : 'database');
139
        $this->printTabs($subject, 'browse');
140
141
        // This code is used when browsing FK in pure-xHTML (without js)
142
        if (isset($_REQUEST['fkey'])) {
143
            $ops = [];
144
            foreach ($_REQUEST['fkey'] as $x => $y) {
145
                $ops[$x] = '=';
146
            }
147
            $query             = $data->getSelectSQL($_REQUEST['table'], [], $_REQUEST['fkey'], $ops);
148
            $_REQUEST['query'] = $query;
149
        }
150
151
        if (isset($object)) {
152
            if (isset($_REQUEST['query'])) {
153
                $_SESSION['sqlquery'] = $_REQUEST['query'];
154
                $this->printTitle($lang['strselect']);
155
                $type = 'SELECT';
156
            } else {
157
                $type = 'TABLE';
158
            }
159
        } else {
160
            $this->printTitle($lang['strqueryresults']);
161
            // we comes from sql.php, $_SESSION['sqlquery'] has been set there
162
            $type = 'QUERY';
163
        }
164
165
        $this->printMsg($msg);
166
167
        // If 'sortkey' is not set, default to ''
168
        if (!isset($_REQUEST['sortkey'])) {
169
            $_REQUEST['sortkey'] = '';
170
        }
171
172
        // If 'sortdir' is not set, default to ''
173
        if (!isset($_REQUEST['sortdir'])) {
174
            $_REQUEST['sortdir'] = '';
175
        }
176
177
        // If 'strings' is not set, default to collapsed
178
        if (!isset($_REQUEST['strings'])) {
179
            $_REQUEST['strings'] = 'collapsed';
180
        }
181
182
        // Fetch unique row identifier, if this is a table browse request.
183
        if (isset($object)) {
184
            $key = $data->getRowIdentifier($object);
185
        } else {
186
            $key = [];
187
        }
188
189
        // Set the schema search path
190
        if (isset($_REQUEST['search_path'])) {
191
            if (0 != $data->setSearchPath(array_map('trim', explode(',', $_REQUEST['search_path'])))) {
192
                return;
193
            }
194
        }
195
196
        try {
197
            // Retrieve page from query.  $max_pages is returned by reference.
198
            $rs = $data->browseQuery(
199
                $type,
200
                isset($object) ? $object : null,
201
                isset($_SESSION['sqlquery']) ? $_SESSION['sqlquery'] : null,
202
                $_REQUEST['sortkey'],
203
                $_REQUEST['sortdir'],
204
                $_REQUEST['page'],
205
                $conf['max_rows'],
206
                $max_pages
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $max_pages seems to be never defined.
Loading history...
207
            );
208
        } catch (\PHPPgAdmin\ADOdbException $e) {
209
            return;
210
        }
211
212
        $fkey_information = $this->getFKInfo();
213
214
        // Build strings for GETs in array
215
        $_gets = [
216
            'server'   => $_REQUEST['server'],
217
            'database' => $_REQUEST['database'],
218
        ];
219
220
        if (isset($_REQUEST['schema'])) {
221
            $_gets['schema'] = $_REQUEST['schema'];
222
        }
223
224
        if (isset($object)) {
225
            $_gets[$subject] = $object;
226
        }
227
228
        if (isset($subject)) {
229
            $_gets['subject'] = $subject;
230
        }
231
232
        if (isset($_REQUEST['query'])) {
233
            $_gets['query'] = $_REQUEST['query'];
234
        }
235
236
        if (isset($_REQUEST['count'])) {
237
            $_gets['count'] = $_REQUEST['count'];
238
        }
239
240
        if (isset($_REQUEST['return'])) {
241
            $_gets['return'] = $_REQUEST['return'];
242
        }
243
244
        if (isset($_REQUEST['search_path'])) {
245
            $_gets['search_path'] = $_REQUEST['search_path'];
246
        }
247
248
        if (isset($_REQUEST['table'])) {
249
            $_gets['table'] = $_REQUEST['table'];
250
        }
251
252
        if (isset($_REQUEST['sortkey'])) {
253
            $_gets['sortkey'] = $_REQUEST['sortkey'];
254
        }
255
256
        if (isset($_REQUEST['sortdir'])) {
257
            $_gets['sortdir'] = $_REQUEST['sortdir'];
258
        }
259
260
        if (isset($_REQUEST['nohistory'])) {
261
            $_gets['nohistory'] = $_REQUEST['nohistory'];
262
        }
263
264
        $_gets['strings'] = $_REQUEST['strings'];
265
266
        if ($save_history && is_object($rs) && ('QUERY' == $type)) {
267
            //{
268
            $this->misc->saveScriptHistory($_REQUEST['query']);
269
        }
270
271
        if (isset($_REQUEST['query'])) {
272
            $query = $_REQUEST['query'];
273
        } else {
274
            $query = "SELECT * FROM {$_REQUEST['schema']}";
275
            if ('matview' == $_REQUEST['subject']) {
276
                $query = "{$query}.{$_REQUEST['matview']};";
277
            } elseif ('view' == $_REQUEST['subject']) {
278
                $query = "{$query}.{$_REQUEST['view']};";
279
            } else {
280
                $query = "{$query}.{$_REQUEST['table']};";
281
            }
282
        }
283
        //$query = isset($_REQUEST['query'])? $_REQUEST['query'] : "select * from {$_REQUEST['schema']}.{$_REQUEST['table']};";
284
        $this->prtrace($query);
285
        //die(htmlspecialchars($query));
286
287
        echo '<form method="post" id="sqlform" action="'.$_SERVER['REQUEST_URI'].'">';
288
        echo '<textarea width="90%" name="query"  id="query" rows="5" cols="100" resizable="true">';
289
290
        echo htmlspecialchars($query);
291
        echo '</textarea><br><input type="submit"/></form>';
292
293
        if (is_object($rs) && $rs->recordCount() > 0) {
294
            // Show page navigation
295
            $this->misc->printPages($_REQUEST['page'], $max_pages, $_gets);
296
297
            echo "<table id=\"data\">\n<tr>";
298
299
            // Check that the key is actually in the result set.  This can occur for select
300
            // operations where the key fields aren't part of the select.  XXX:  We should
301
            // be able to support this, somehow.
302
            foreach ($key as $v) {
303
                // If a key column is not found in the record set, then we
304
                // can't use the key.
305
                if (!in_array($v, array_keys($rs->fields), true)) {
306
                    $key = [];
307
308
                    break;
309
                }
310
            }
311
312
            $buttons = [
313
                'edit' => [
314
                    'content' => $lang['stredit'],
315
                    'attr'    => [
316
                        'href' => [
317
                            'url'     => 'display.php',
318
                            'urlvars' => array_merge([
319
                                'action'  => 'confeditrow',
320
                                'strings' => $_REQUEST['strings'],
321
                                'page'    => $_REQUEST['page'],
322
                            ], $_gets),
323
                        ],
324
                    ],
325
                ],
326
                'delete' => [
327
                    'content' => $lang['strdelete'],
328
                    'attr'    => [
329
                        'href' => [
330
                            'url'     => 'display.php',
331
                            'urlvars' => array_merge([
332
                                'action'  => 'confdelrow',
333
                                'strings' => $_REQUEST['strings'],
334
                                'page'    => $_REQUEST['page'],
335
                            ], $_gets),
336
                        ],
337
                    ],
338
                ],
339
            ];
340
            $actions = [
341
                'actionbuttons' => &$buttons,
342
                'place'         => 'display-browse',
343
            ];
344
            $plugin_manager->do_hook('actionbuttons', $actions);
345
346
            foreach (array_keys($actions['actionbuttons']) as $action) {
347
                $actions['actionbuttons'][$action]['attr']['href']['urlvars'] = array_merge(
348
                    $actions['actionbuttons'][$action]['attr']['href']['urlvars'],
349
                    $_gets
350
                );
351
            }
352
353
            $edit_params = isset($actions['actionbuttons']['edit']) ?
354
            $actions['actionbuttons']['edit'] : [];
355
            $delete_params = isset($actions['actionbuttons']['delete']) ?
356
            $actions['actionbuttons']['delete'] : [];
357
358
            // Display edit and delete actions if we have a key
359
            $colspan = count($buttons);
360
            if ($colspan > 0 and count($key) > 0) {
361
                echo "<th colspan=\"{$colspan}\" class=\"data\">{$lang['stractions']}</th>"."\n";
362
            }
363
364
            // we show OIDs only if we are in TABLE or SELECT type browsing
365
            $this->printTableHeaderCells($rs, $_gets, isset($object));
366
367
            echo '</tr>'."\n";
368
369
            $i = 0;
370
            reset($rs->fields);
371
            while (!$rs->EOF) {
372
                $id = (0 == ($i % 2) ? '1' : '2');
373
                echo "<tr class=\"data{$id}\">"."\n";
374
                // Display edit and delete links if we have a key
375
                if ($colspan > 0 and count($key) > 0) {
376
                    $keys_array = [];
377
                    $has_nulls  = false;
378
                    foreach ($key as $v) {
379
                        if (null === $rs->fields[$v]) {
380
                            $has_nulls = true;
381
382
                            break;
383
                        }
384
                        $keys_array["key[{$v}]"] = $rs->fields[$v];
385
                    }
386
                    if ($has_nulls) {
387
                        echo "<td colspan=\"{$colspan}\">&nbsp;</td>"."\n";
388
                    } else {
389
                        if (isset($actions['actionbuttons']['edit'])) {
390
                            $actions['actionbuttons']['edit']                            = $edit_params;
391
                            $actions['actionbuttons']['edit']['attr']['href']['urlvars'] = array_merge(
392
                                $actions['actionbuttons']['edit']['attr']['href']['urlvars'],
393
                                $keys_array
394
                            );
395
                        }
396
397
                        if (isset($actions['actionbuttons']['delete'])) {
398
                            $actions['actionbuttons']['delete']                            = $delete_params;
399
                            $actions['actionbuttons']['delete']['attr']['href']['urlvars'] = array_merge(
400
                                $actions['actionbuttons']['delete']['attr']['href']['urlvars'],
401
                                $keys_array
402
                            );
403
                        }
404
405
                        foreach ($actions['actionbuttons'] as $action) {
406
                            echo "<td class=\"opbutton{$id}\">";
407
                            $this->printLink($action, true, __METHOD__);
408
                            echo '</td>'."\n";
409
                        }
410
                    }
411
                }
412
413
                $this->printTableRowCells($rs, $fkey_information, isset($object));
414
415
                echo '</tr>'."\n";
416
                $rs->moveNext();
417
                ++$i;
418
            }
419
            echo '</table>'."\n";
420
421
            echo '<p>', $rs->recordCount(), " {$lang['strrows']}</p>"."\n";
422
            // Show page navigation
423
            $this->misc->printPages($_REQUEST['page'], $max_pages, $_gets);
424
        } else {
425
            echo "<p>{$lang['strnodata']}</p>"."\n";
426
        }
427
428
        // Navigation links
429
        $navlinks = [];
430
431
        $fields = [
432
            'server'   => $_REQUEST['server'],
433
            'database' => $_REQUEST['database'],
434
        ];
435
436
        if (isset($_REQUEST['schema'])) {
437
            $fields['schema'] = $_REQUEST['schema'];
438
        }
439
440
        // Return
441
        if (isset($_REQUEST['return'])) {
442
            $urlvars = $this->misc->getSubjectParams($_REQUEST['return']);
443
444
            $navlinks['back'] = [
445
                'attr' => [
446
                    'href' => [
447
                        'url'     => $urlvars['url'],
448
                        'urlvars' => $urlvars['params'],
449
                    ],
450
                ],
451
                'content' => $lang['strback'],
452
            ];
453
        }
454
455
        // Edit SQL link
456
        if ('QUERY' == $type) {
457
            $navlinks['edit'] = [
458
                'attr' => [
459
                    'href' => [
460
                        'url'     => 'database.php',
461
                        'urlvars' => array_merge($fields, [
462
                            'action'   => 'sql',
463
                            'paginate' => 'on',
464
                        ]),
465
                    ],
466
                ],
467
                'content' => $lang['streditsql'],
468
            ];
469
        }
470
471
        // Expand/Collapse
472
        if ('expanded' == $_REQUEST['strings']) {
473
            $navlinks['collapse'] = [
474
                'attr' => [
475
                    'href' => [
476
                        'url'     => 'display.php',
477
                        'urlvars' => array_merge(
478
                            $_gets,
479
                            [
480
                                'strings' => 'collapsed',
481
                                'page'    => $_REQUEST['page'],
482
                            ]
483
                        ),
484
                    ],
485
                ],
486
                'content' => $lang['strcollapse'],
487
            ];
488
        } else {
489
            $navlinks['collapse'] = [
490
                'attr' => [
491
                    'href' => [
492
                        'url'     => 'display.php',
493
                        'urlvars' => array_merge(
494
                            $_gets,
495
                            [
496
                                'strings' => 'expanded',
497
                                'page'    => $_REQUEST['page'],
498
                            ]
499
                        ),
500
                    ],
501
                ],
502
                'content' => $lang['strexpand'],
503
            ];
504
        }
505
506
        // Create view and download
507
        if (isset($_REQUEST['query'], $rs) && is_object($rs) && $rs->recordCount() > 0) {
508
            // Report views don't set a schema, so we need to disable create view in that case
509
            if (isset($_REQUEST['schema'])) {
510
                $navlinks['createview'] = [
511
                    'attr' => [
512
                        'href' => [
513
                            'url'     => 'views.php',
514
                            'urlvars' => array_merge($fields, [
515
                                'action'         => 'create',
516
                                'formDefinition' => $_REQUEST['query'],
517
                            ]),
518
                        ],
519
                    ],
520
                    'content' => $lang['strcreateview'],
521
                ];
522
            }
523
524
            $urlvars = [];
525
            if (isset($_REQUEST['search_path'])) {
526
                $urlvars['search_path'] = $_REQUEST['search_path'];
527
            }
528
529
            $navlinks['download'] = [
530
                'attr' => [
531
                    'href' => [
532
                        'url'     => 'dataexport.php',
533
                        'urlvars' => array_merge($fields, $urlvars),
534
                    ],
535
                ],
536
                'content' => $lang['strdownload'],
537
            ];
538
        }
539
540
        // Insert
541
        if (isset($object) && (isset($subject) && 'table' == $subject)) {
542
            $navlinks['insert'] = [
543
                'attr' => [
544
                    'href' => [
545
                        'url'     => 'tables.php',
546
                        'urlvars' => array_merge($fields, [
547
                            'action' => 'confinsertrow',
548
                            'table'  => $object,
549
                        ]),
550
                    ],
551
                ],
552
                'content' => $lang['strinsert'],
553
            ];
554
        }
555
556
        // Refresh
557
        $navlinks['refresh'] = [
558
            'attr' => [
559
                'href' => [
560
                    'url'     => 'display.php',
561
                    'urlvars' => array_merge(
562
                        $_gets,
563
                        [
564
                            'strings' => $_REQUEST['strings'],
565
                            'page'    => $_REQUEST['page'],
566
                        ]
567
                    ),
568
                ],
569
            ],
570
            'content' => $lang['strrefresh'],
571
        ];
572
573
        $this->printNavLinks($navlinks, 'display-browse', get_defined_vars());
574
    }
575
576
    /**
577
     * Show confirmation of edit and perform actual update.
578
     *
579
     * @param mixed $confirm
1 ignored issue
show
Missing parameter comment
Loading history...
580
     * @param mixed $msg
1 ignored issue
show
Missing parameter comment
Loading history...
581
     */
582
    public function doEditRow($confirm, $msg = '')
583
    {
584
        $conf = $this->conf;
585
586
        $lang = $this->lang;
587
        $data = $this->misc->getDatabaseAccessor();
588
589
        if (is_array($_REQUEST['key'])) {
590
            $key = $_REQUEST['key'];
591
        } else {
592
            $key = unserialize(urldecode($_REQUEST['key']));
593
        }
594
595
        if ($confirm) {
596
            $this->printTrail($_REQUEST['subject']);
597
            $this->printTitle($lang['streditrow']);
598
            $this->printMsg($msg);
599
600
            $attrs = $data->getTableAttributes($_REQUEST['table']);
601
            $rs    = $data->browseRow($_REQUEST['table'], $key);
602
603
            if (('disable' != $conf['autocomplete'])) {
604
                $fksprops = $this->misc->getAutocompleteFKProperties($_REQUEST['table']);
605
                if (false !== $fksprops) {
606
                    echo $fksprops['code'];
607
                }
608
            } else {
609
                $fksprops = false;
610
            }
611
612
            echo '<form action="'.\SUBFOLDER.'/src/views/display.php" method="post" id="ac_form">'."\n";
613
614
            /*echo '<p>';
615
            if (!$error) {
616
            echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$lang['strsave']}\" />" . "\n";
617
            }
618
619
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
620
621
            echo '</p>' . "\n";*/
622
623
            $elements = 0;
624
            $error    = true;
625
            if (1 == $rs->recordCount() && $attrs->recordCount() > 0) {
626
                echo '<table>'."\n";
627
628
                // Output table header
629
                echo "<tr><th class=\"data\">{$lang['strcolumn']}</th><th class=\"data\">{$lang['strtype']}</th>";
630
                echo "<th class=\"data\">{$lang['strformat']}</th>"."\n";
631
                echo "<th class=\"data\">{$lang['strnull']}</th><th class=\"data\">{$lang['strvalue']}</th></tr>";
632
633
                $i = 0;
634
                while (!$attrs->EOF) {
635
                    $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']);
636
                    $id                          = (0 == ($i % 2) ? '1' : '2');
637
638
                    // Initialise variables
639
                    if (!isset($_REQUEST['format'][$attrs->fields['attname']])) {
640
                        $_REQUEST['format'][$attrs->fields['attname']] = 'VALUE';
641
                    }
642
643
                    echo "<tr class=\"data{$id}\">"."\n";
644
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($attrs->fields['attname']), '</td>';
645
                    echo '<td style="white-space:nowrap;">'."\n";
646
                    echo $this->misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod']));
647
                    echo '<input type="hidden" name="types[', htmlspecialchars($attrs->fields['attname']), ']" value="',
648
                    htmlspecialchars($attrs->fields['type']), '" /></td>';
649
                    ++$elements;
650
                    echo '<td style="white-space:nowrap;">'."\n";
651
                    echo '<select name="format['.htmlspecialchars($attrs->fields['attname']), ']">'."\n";
652
                    echo '<option value="VALUE"', ($_REQUEST['format'][$attrs->fields['attname']] == 'VALUE') ? ' selected="selected"' : '', ">{$lang['strvalue']}</option>"."\n";
653
                    $selected = ($_REQUEST['format'][$attrs->fields['attname']] == 'EXPRESSION') ? ' selected="selected"' : '';
654
                    echo '<option value="EXPRESSION"'.$selected.">{$lang['strexpression']}</option>"."\n";
655
                    echo "</select>\n</td>"."\n";
656
                    ++$elements;
657
                    echo '<td style="white-space:nowrap;">';
658
                    // Output null box if the column allows nulls (doesn't look at CHECKs or ASSERTIONS)
659
                    if (!$attrs->fields['attnotnull']) {
660
                        // Set initial null values
661
                        if ('confeditrow' == $_REQUEST['action'] && null === $rs->fields[$attrs->fields['attname']]) {
662
                            $_REQUEST['nulls'][$attrs->fields['attname']] = 'on';
663
                        }
664
                        echo "<label><span><input type=\"checkbox\" name=\"nulls[{$attrs->fields['attname']}]\"",
665
                        isset($_REQUEST['nulls'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></span></label></td>'."\n";
666
                        ++$elements;
667
                    } else {
668
                        echo '&nbsp;</td>';
669
                    }
670
671
                    echo "<td id=\"row_att_{$attrs->fields['attnum']}\" style=\"white-space:nowrap;\">";
672
673
                    $extras = [];
674
675
                    // If the column allows nulls, then we put a JavaScript action on the data field to unset the
676
                    // NULL checkbox as soon as anything is entered in the field.  We use the $elements variable to
677
                    // keep track of which element offset we're up to.  We can't refer to the null checkbox by name
678
                    // as it contains '[' and ']' characters.
679
                    if (!$attrs->fields['attnotnull']) {
680
                        $extras['onChange'] = 'elements['.($elements - 1).'].checked = false;';
681
                    }
682
683
                    if ((false !== $fksprops) && isset($fksprops['byfield'][$attrs->fields['attnum']])) {
684
                        $extras['id']           = "attr_{$attrs->fields['attnum']}";
685
                        $extras['autocomplete'] = 'off';
686
                    }
687
688
                    echo $data->printField("values[{$attrs->fields['attname']}]", $rs->fields[$attrs->fields['attname']], $attrs->fields['type'], $extras);
689
690
                    echo '</td>';
691
                    ++$elements;
692
                    echo '</tr>'."\n";
693
                    ++$i;
694
                    $attrs->moveNext();
695
                }
696
                echo '</table>'."\n";
697
698
                $error = false;
699
            } elseif (1 != $rs->recordCount()) {
700
                echo "<p>{$lang['strrownotunique']}</p>"."\n";
701
            } else {
702
                echo "<p>{$lang['strinvalidparam']}</p>"."\n";
703
            }
704
705
            echo '<input type="hidden" name="action" value="editrow" />'."\n";
706
            echo $this->misc->form;
707
            if (isset($_REQUEST['table'])) {
708
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />'."\n";
709
            }
710
711
            if (isset($_REQUEST['subject'])) {
712
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />'."\n";
713
            }
714
715
            if (isset($_REQUEST['query'])) {
716
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />'."\n";
717
            }
718
719
            if (isset($_REQUEST['count'])) {
720
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />'."\n";
721
            }
722
723
            if (isset($_REQUEST['return'])) {
724
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />'."\n";
725
            }
726
727
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />'."\n";
728
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />'."\n";
729
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />'."\n";
730
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />'."\n";
731
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($key))), '" />'."\n";
732
            echo '<p>';
733
            if (!$error) {
734
                echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$lang['strsave']}\" />"."\n";
735
            }
736
737
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />"."\n";
738
739
            if (false !== $fksprops) {
740
                if ('default off' != $conf['autocomplete']) {
741
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"1\" checked=\"checked\" /><label for=\"no_ac\">{$lang['strac']}</label>"."\n";
742
                } else {
743
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"0\" /><label for=\"no_ac\">{$lang['strac']}</label>"."\n";
744
                }
745
            }
746
747
            echo '</p>'."\n";
748
            echo '</form>'."\n";
749
        } else {
750
            if (!isset($_POST['values'])) {
751
                $_POST['values'] = [];
752
            }
753
754
            if (!isset($_POST['nulls'])) {
755
                $_POST['nulls'] = [];
756
            }
757
758
            $status = $data->editRow(
759
                $_POST['table'],
760
                $_POST['values'],
761
                $_POST['nulls'],
762
                $_POST['format'],
763
                $_POST['types'],
764
                $key
765
            );
766
            if (0 == $status) {
767
                $this->doBrowse($lang['strrowupdated']);
768
            } elseif ($status == -2) {
769
                $this->doEditRow(true, $lang['strrownotunique']);
770
            } else {
771
                $this->doEditRow(true, $lang['strrowupdatedbad']);
772
            }
773
        }
774
    }
775
776
    /**
777
     * Show confirmation of drop and perform actual drop.
778
     *
779
     * @param mixed $confirm
1 ignored issue
show
Missing parameter comment
Loading history...
780
     */
781
    public function doDelRow($confirm)
782
    {
783
        $conf = $this->conf;
784
785
        $lang = $this->lang;
786
        $data = $this->misc->getDatabaseAccessor();
787
788
        if ($confirm) {
789
            $this->printTrail($_REQUEST['subject']);
790
            $this->printTitle($lang['strdeleterow']);
791
792
            $rs = $data->browseRow($_REQUEST['table'], $_REQUEST['key']);
793
794
            echo '<form action="'.\SUBFOLDER.'/src/views/display.php" method="post">'."\n";
795
            echo $this->misc->form;
796
797
            if (1 == $rs->recordCount()) {
798
                echo "<p>{$lang['strconfdeleterow']}</p>"."\n";
799
800
                $fkinfo = [];
801
                echo '<table><tr>';
802
                $this->printTableHeaderCells($rs, false, true);
803
                echo '</tr>';
804
                echo '<tr class="data1">'."\n";
805
                $this->printTableRowCells($rs, $fkinfo, true);
806
                echo '</tr>'."\n";
807
                echo '</table>'."\n";
808
                echo '<br />'."\n";
809
810
                echo '<input type="hidden" name="action" value="delrow" />'."\n";
811
                echo "<input type=\"submit\" name=\"yes\" value=\"{$lang['stryes']}\" />"."\n";
812
                echo "<input type=\"submit\" name=\"no\" value=\"{$lang['strno']}\" />"."\n";
813
            } elseif (1 != $rs->recordCount()) {
814
                echo "<p>{$lang['strrownotunique']}</p>"."\n";
815
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />"."\n";
816
            } else {
817
                echo "<p>{$lang['strinvalidparam']}</p>"."\n";
818
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />"."\n";
819
            }
820
            if (isset($_REQUEST['table'])) {
821
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />'."\n";
822
            }
823
824
            if (isset($_REQUEST['subject'])) {
825
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />'."\n";
826
            }
827
828
            if (isset($_REQUEST['query'])) {
829
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />'."\n";
830
            }
831
832
            if (isset($_REQUEST['count'])) {
833
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />'."\n";
834
            }
835
836
            if (isset($_REQUEST['return'])) {
837
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />'."\n";
838
            }
839
840
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />'."\n";
841
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />'."\n";
842
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />'."\n";
843
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />'."\n";
844
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($_REQUEST['key']))), '" />'."\n";
845
            echo '</form>'."\n";
846
        } else {
847
            $status = $data->deleteRow($_POST['table'], unserialize(urldecode($_POST['key'])));
848
            if (0 == $status) {
849
                $this->doBrowse($lang['strrowdeleted']);
850
            } elseif ($status == -2) {
851
                $this->doBrowse($lang['strrownotunique']);
852
            } else {
853
                $this->doBrowse($lang['strrowdeletedbad']);
854
            }
855
        }
856
    }
857
858
    /**
859
     * build & return the FK information data structure
860
     * used when deciding if a field should have a FK link or not.
861
     *
862
     * @return [type] [description]
863
     */
864
    public function &getFKInfo()
865
    {
866
        $conf = $this->conf;
867
868
        $lang = $this->lang;
0 ignored issues
show
The assignment to $lang is dead and can be removed.
Loading history...
869
        $data = $this->misc->getDatabaseAccessor();
870
871
        // Get the foreign key(s) information from the current table
872
        $fkey_information = ['byconstr' => [], 'byfield' => []];
873
874
        if (isset($_REQUEST['table'])) {
875
            $constraints = $data->getConstraintsWithFields($_REQUEST['table']);
876
            if ($constraints->recordCount() > 0) {
877
                $fkey_information['common_url'] = $this->misc->getHREF('schema').'&amp;subject=table';
878
879
                // build the FK constraints data structure
880
                while (!$constraints->EOF) {
881
                    $constr = &$constraints->fields;
882
                    if ('f' == $constr['contype']) {
883
                        if (!isset($fkey_information['byconstr'][$constr['conid']])) {
884
                            $fkey_information['byconstr'][$constr['conid']] = [
885
                                'url_data' => 'table='.urlencode($constr['f_table']).'&amp;schema='.urlencode($constr['f_schema']),
886
                                'fkeys'    => [],
887
                                'consrc'   => $constr['consrc'],
888
                            ];
889
                        }
890
891
                        $fkey_information['byconstr'][$constr['conid']]['fkeys'][$constr['p_field']] = $constr['f_field'];
892
893
                        if (!isset($fkey_information['byfield'][$constr['p_field']])) {
894
                            $fkey_information['byfield'][$constr['p_field']] = [];
895
                        }
896
897
                        $fkey_information['byfield'][$constr['p_field']][] = $constr['conid'];
898
                    }
899
                    $constraints->moveNext();
900
                }
901
            }
902
        }
903
904
        return $fkey_information;
905
    }
906
907
    /**
908
     * Print table header cells.
909
     *
910
     * @param $args - associative array for sort link parameters
911
     * @param mixed $withOid
1 ignored issue
show
Missing parameter comment
Loading history...
Doc comment for parameter $withOid does not match actual variable name $args
Loading history...
912
     */
913
    public function printTableHeaderCells(&$rs, $args, $withOid)
914
    {
915
        $conf = $this->conf;
916
917
        $lang = $this->lang;
0 ignored issues
show
The assignment to $lang is dead and can be removed.
Loading history...
918
        $data = $this->misc->getDatabaseAccessor();
919
        $j    = 0;
920
921
        foreach ($rs->fields as $k => $v) {
922
            if (($k === $data->id) && (!($withOid && $conf['show_oids']))) {
923
                ++$j;
924
925
                continue;
926
            }
927
            $finfo = $rs->fetchField($j);
928
929
            if (false === $args) {
930
                echo '<th class="data">', $this->misc->printVal($finfo->name), '</th>'."\n";
931
            } else {
932
                $args['page']    = $_REQUEST['page'];
933
                $args['sortkey'] = $j + 1;
934
                // Sort direction opposite to current direction, unless it's currently ''
935
                $args['sortdir'] = (
936
                    'asc' == $_REQUEST['sortdir']
937
                    and $_REQUEST['sortkey'] == ($j + 1)
938
                ) ? 'desc' : 'asc';
939
940
                $sortLink = http_build_query($args);
941
942
                echo "<th class=\"data\"><a href=\"?{$sortLink}\">"
943
                , $this->misc->printVal($finfo->name);
944
                if ($_REQUEST['sortkey'] == ($j + 1)) {
945
                    if ('asc' == $_REQUEST['sortdir']) {
946
                        echo '<img src="'.$this->misc->icon('RaiseArgument').'" alt="asc">';
947
                    } else {
948
                        echo '<img src="'.$this->misc->icon('LowerArgument').'" alt="desc">';
949
                    }
950
                }
951
                echo '</a></th>'."\n";
952
            }
953
            ++$j;
954
        }
955
956
        reset($rs->fields);
957
    }
958
959
    // Print data-row cells
960
    public function printTableRowCells(&$rs, &$fkey_information, $withOid)
961
    {
962
        $conf = $this->conf;
963
964
        $lang = $this->lang;
0 ignored issues
show
The assignment to $lang is dead and can be removed.
Loading history...
965
        $data = $this->misc->getDatabaseAccessor();
966
        $j    = 0;
967
968
        if (!isset($_REQUEST['strings'])) {
969
            $_REQUEST['strings'] = 'collapsed';
970
        }
971
972
        foreach ($rs->fields as $k => $v) {
973
            $finfo = $rs->fetchField($j++);
974
975
            if (($k === $data->id) && (!($withOid && $conf['show_oids']))) {
976
                continue;
977
            }
978
            if (null !== $v && '' == $v) {
979
                echo '<td>&nbsp;</td>';
980
            } else {
981
                echo '<td style="white-space:nowrap;">';
982
983
                if ((null !== $v) && isset($fkey_information['byfield'][$k])) {
984
                    foreach ($fkey_information['byfield'][$k] as $conid) {
985
                        $query_params = $fkey_information['byconstr'][$conid]['url_data'];
986
987
                        foreach ($fkey_information['byconstr'][$conid]['fkeys'] as $p_field => $f_field) {
988
                            $query_params .= '&amp;'.urlencode("fkey[{$f_field}]").'='.urlencode($rs->fields[$p_field]);
989
                        }
990
991
                        // $fkey_information['common_url'] is already urlencoded
992
                        $query_params .= '&amp;'.$fkey_information['common_url'];
993
                        echo '<div style="display:inline-block;">';
994
                        echo '<a class="fk fk_'.htmlentities($conid, ENT_QUOTES, 'UTF-8')."\" href=\"display.php?{$query_params}\">";
995
                        echo '<img src="'.$this->misc->icon('ForeignKey').'" style="vertical-align:middle;" alt="[fk]" title="'
996
                        .htmlentities($fkey_information['byconstr'][$conid]['consrc'], ENT_QUOTES, 'UTF-8')
997
                            .'" />';
998
                        echo '</a>';
999
                        echo '</div>';
1000
                    }
1001
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings']), 'class' => 'fk_value']);
1002
                } else {
1003
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings'])]);
1004
                }
1005
                echo '</td>';
1006
            }
1007
        }
1008
    }
1009
1010
    // Print the FK row, used in ajax requests
1011
    public function doBrowseFK()
1012
    {
1013
        $conf = $this->conf;
1014
1015
        $lang = $this->lang;
1016
        $data = $this->misc->getDatabaseAccessor();
1017
1018
        $ops = [];
1019
        foreach ($_REQUEST['fkey'] as $x => $y) {
1020
            $ops[$x] = '=';
1021
        }
1022
        $query             = $data->getSelectSQL($_REQUEST['table'], [], $_REQUEST['fkey'], $ops);
1023
        $_REQUEST['query'] = $query;
1024
1025
        $fkinfo = $this->getFKInfo();
1026
1027
        $max_pages = 1;
1028
        // Retrieve page from query.  $max_pages is returned by reference.
1029
        $rs = $data->browseQuery(
1030
            'SELECT',
1031
            $_REQUEST['table'],
1032
            $_REQUEST['query'],
1033
            null,
1034
            null,
1035
            1,
1036
            1,
1037
            $max_pages
1038
        );
1039
1040
        echo '<a href="javascript:void(0);" style="display:table-cell;" class="fk_delete"><img alt="[delete]" src="'.$this->misc->icon('Delete').'" /></a>'."\n";
1041
        echo '<div style="display:table-cell;">';
1042
1043
        if (is_object($rs) && $rs->recordCount() > 0) {
1044
            /* we are browsing a referenced table here
1045
             * we should show OID if show_oids is true
1046
             * so we give true to withOid in functions bellow
1047
             */
1048
            echo '<table><tr>';
1049
            $this->printTableHeaderCells($rs, false, true);
1050
            echo '</tr>';
1051
            echo '<tr class="data1">'."\n";
1052
            $this->printTableRowCells($rs, $fkinfo, true);
1053
            echo '</tr>'."\n";
1054
            echo '</table>'."\n";
1055
        } else {
1056
            echo $lang['strnodata'];
1057
        }
1058
        echo '</div>';
1059
    }
1060
}
1061