DataexportController::render()   C
last analyzed

Complexity

Conditions 14
Paths 12

Size

Total Lines 67
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 32
c 1
b 0
f 0
nc 12
nop 0
dl 0
loc 67
rs 6.2666

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * PHPPgAdmin 6.1.3
5
 */
6
7
namespace PHPPgAdmin\Controller;
8
9
/**
10
 * Base controller class.
11
 */
12
class DataexportController extends BaseController
13
{
14
    public $extensions = [
15
        'sql' => 'sql',
16
        'copy' => 'sql',
17
        'csv' => 'csv',
18
        'tab' => 'txt',
19
        'html' => 'html',
20
        'xml' => 'xml',
21
    ];
22
23
    public $controller_title = 'strexport';
24
25
    /**
26
     * Default method to render the controller according to the action parameter.
27
     */
28
    public function render()
29
    {
30
        \set_time_limit(0);
31
32
        // if (!isset($_REQUEST['table']) && !isset($_REQUEST['query']))
33
        // What must we do in this case? Maybe redirect to the homepage?
34
35
        $format = 'N/A';
36
37
        // force behavior to assume there is no pg_dump in the system
38
        $forcemimic = $_REQUEST['forcemimic'] ?? false;
39
40
        // If format is set, then perform the export
41
        if (!isset($_REQUEST['what'])) {
42
            return $this->doDefault();
43
        }
44
45
        //$this->prtrace("REQUEST['what']", $_REQUEST['what']);
46
47
        // Include application functions
48
        $this->setNoOutput(true);
49
        $clean = false;
50
        $oids = false;
51
52
        switch ($_REQUEST['what']) {
53
            case 'dataonly':
54
                // Check to see if they have pg_dump set up and if they do, use that
55
                // instead of custom dump code
56
                if (!$forcemimic && $this->misc->isDumpEnabled() && ('copy' === $_REQUEST['d_format'] || 'sql' === $_REQUEST['d_format'])) {
57
                    //$this->prtrace('DUMP ENABLED, d_format is', $_REQUEST['d_format']);
58
                    $dbexport_controller = new \PHPPgAdmin\Controller\DbexportController($this->getContainer());
59
60
                    return $dbexport_controller->render();
61
                }
62
63
                $format = $_REQUEST['d_format'];
64
                $oids = isset($_REQUEST['d_oids']);
65
66
                break;
67
            case 'structureonly':
68
                // Check to see if they have pg_dump set up and if they do, use that
69
                // instead of custom dump code
70
                if (!$forcemimic && $this->misc->isDumpEnabled()) {
71
                    $dbexport_controller = new \PHPPgAdmin\Controller\DbexportController($this->getContainer());
72
73
                    return $dbexport_controller->render();
74
                }
75
                $clean = isset($_REQUEST['s_clean']);
76
77
                break;
78
            case 'structureanddata':
79
                // Check to see if they have pg_dump set up and if they do, use that
80
                // instead of custom dump code
81
                if (!$forcemimic && $this->misc->isDumpEnabled()) {
82
                    $dbexport_controller = new \PHPPgAdmin\Controller\DbexportController($this->getContainer());
83
84
                    return $dbexport_controller->render();
85
                }
86
                $format = $_REQUEST['sd_format'];
87
                $clean = isset($_REQUEST['sd_clean']);
88
                $oids = isset($_REQUEST['sd_oids']);
89
90
                break;
91
        }
92
        $cleanprefix = $clean ? '' : '-- ';
93
94
        return $this->mimicDumpFeature($format, $cleanprefix, $oids);
95
    }
96
97
    public function doDefault($msg = ''): void
98
    {
99
        if (!isset($_REQUEST['query']) || empty($_REQUEST['query'])) {
100
            $_REQUEST['query'] = $_SESSION['sqlquery'];
101
        }
102
103
        $this->printHeader();
104
        $this->printBody();
105
        $this->printTrail($_REQUEST['subject'] ?? 'database');
106
        $this->printTitle($this->lang['strexport']);
107
108
        if (isset($msg)) {
109
            $this->printMsg($msg);
110
        }
111
112
        echo '<form action="' . \containerInstance()->subFolder . '/src/views/dataexport" method="post">' . \PHP_EOL;
113
        echo '<table>' . \PHP_EOL;
114
        echo "<tr><th class=\"data\">{$this->lang['strformat']}:</th><td><select name=\"d_format\">" . \PHP_EOL;
115
        // COPY and SQL require a table
116
        if (isset($_REQUEST['table'])) {
117
            echo '<option value="copy">COPY</option>' . \PHP_EOL;
118
            echo '<option value="sql">SQL</option>' . \PHP_EOL;
119
        }
120
        echo '<option value="csv">CSV</option>' . \PHP_EOL;
121
        echo "<option value=\"tab\">{$this->lang['strtabbed']}</option>" . \PHP_EOL;
122
        echo '<option value="html">XHTML</option>' . \PHP_EOL;
123
        echo '<option value="xml">XML</option>' . \PHP_EOL;
124
        echo '</select></td></tr>';
125
        echo '</table>' . \PHP_EOL;
126
127
        echo "<h3>{$this->lang['stroptions']}</h3>" . \PHP_EOL;
128
        echo "<p><input type=\"radio\" id=\"output1\" name=\"output\" value=\"show\" checked=\"checked\" /><label for=\"output1\">{$this->lang['strshow']}</label>" . \PHP_EOL;
129
        echo "<br/><input type=\"radio\" id=\"output2\" name=\"output\" value=\"download\" /><label for=\"output2\">{$this->lang['strdownload']}</label></p>" . \PHP_EOL;
130
131
        echo '<p><input type="hidden" name="action" value="export" />' . \PHP_EOL;
132
        echo '<input type="hidden" name="what" value="dataonly" />' . \PHP_EOL;
133
134
        if (isset($_REQUEST['table'])) {
135
            echo '<input type="hidden" name="subject" value="table" />' . \PHP_EOL;
136
            echo \sprintf('<input type="hidden" name="table" value="%s"  />%s', \htmlspecialchars($_REQUEST['table']), \PHP_EOL);
137
        } else {
138
            echo '<input type="hidden" name="subject" value="table" />' . \PHP_EOL;
139
        }
140
        //$this->prtrace('$_REQUEST[query]', $_REQUEST['query'], \htmlspecialchars(\urlencode($_REQUEST['query'])));
141
        //$this->prtrace('$_SESSION[sqlquery]', $_SESSION['sqlquery'], \htmlspecialchars(\urlencode($_SESSION['sqlquery'])));
142
        echo '<input type="hidden" name="query" value="', \htmlspecialchars(\urlencode($_REQUEST['query'])), '" />' . \PHP_EOL;
143
144
        if (isset($_REQUEST['search_path'])) {
145
            echo '<input type="hidden" name="search_path" value="', \htmlspecialchars($_REQUEST['search_path']), '" />' . \PHP_EOL;
146
        }
147
        echo $this->view->form;
148
        echo "<input type=\"submit\" value=\"{$this->lang['strexport']}\" /></p>" . \PHP_EOL;
149
        echo '</form>' . \PHP_EOL;
150
151
        $this->printFooter();
152
    }
153
154
    protected function mimicDumpFeature($format, string $cleanprefix, bool $oids)
155
    {
156
        $data = $this->misc->getDatabaseAccessor();
157
158
        \set_time_limit(0);
159
160
        // if (!isset($_REQUEST['table']) && !isset($_REQUEST['query']))
161
        // What must we do in this case? Maybe redirect to the homepage?
162
163
        // If format is set, then perform the export
164
        if (!isset($_REQUEST['what'])) {
165
            return $this->doDefault();
166
        }
167
168
        //$this->prtrace("REQUEST['what']", $_REQUEST['what']);
169
170
        // Include application functions
171
        $this->setNoOutput(true);
172
173
        $response = $this->_getResponse($format);
174
175
        $this->coalesceArr($_REQUEST, 'query', '');
176
177
        $_REQUEST['query'] = \trim(\urldecode($_REQUEST['query']));
178
179
        // Set the schema search path
180
        if (isset($_REQUEST['search_path'])) {
181
            $data->setSearchPath(\array_map('trim', \explode(',', $_REQUEST['search_path'])));
182
        } elseif (isset($_REQUEST['schema'])) {
183
            $data->setSearchPath($_REQUEST['schema']);
184
        }
185
186
        $subject = $this->coalesceArr($_REQUEST, 'subject', 'table')['subject'];
187
188
        $object = $this->coalesceArr($_REQUEST, $subject)[$subject];
189
190
        // Set up the dump transaction
191
        $status = $data->beginDump();
192
        //$this->prtrace('subject', $subject);
193
        //$this->prtrace('object', $object);
194
        $tabledefprefix = '';
195
        $tabledefsuffix = '';
196
197
        // If the dump is not dataonly then dump the structure prefix
198
        if ('dataonly' !== $_REQUEST['what']) {
199
            $tabledefprefix = $data->getTableDefPrefix($object, $cleanprefix);
200
            //$this->prtrace('tabledefprefix', $tabledefprefix);
201
            echo $tabledefprefix;
202
        }
203
204
        // If the dump is not structureonly then dump the actual data
205
        if ('structureonly' !== $_REQUEST['what']) {
206
            // Get database encoding
207
            //$dbEncoding = $data->getDatabaseEncoding();
208
209
            // Set fetch mode to NUM so that duplicate field names are properly returned
210
            $data->conn->setFetchMode(\ADODB_FETCH_NUM);
0 ignored issues
show
Bug introduced by
ADODB_FETCH_NUM of type integer is incompatible with the type The expected by parameter $mode of ADOConnection::SetFetchMode(). ( Ignorable by Annotation )

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

210
            $data->conn->setFetchMode(/** @scrutinizer ignore-type */ \ADODB_FETCH_NUM);
Loading history...
211
212
            // Execute the query, if set, otherwise grab all rows from the table
213
            $rs = $this->_getRS($data, $object, $oids);
214
215
            $response = $this->pickFormat($data, $object, $oids, $rs, $format, $response);
216
        }
217
218
        if ('dataonly' !== $_REQUEST['what']) {
219
            $data->conn->setFetchMode(\ADODB_FETCH_ASSOC);
220
            $tabledefsuffix = $data->getTableDefSuffix($object);
221
            //$this->prtrace('tabledefsuffix', $tabledefsuffix);
222
            echo $tabledefsuffix;
223
        }
224
225
        // Finish the dump transaction
226
        $status = $data->endDump();
227
228
        return $response;
229
    }
230
231
    private function _getRS($data, $object, bool $oids)
232
    {
233
        if ($object) {
234
            return $data->dumpRelation($object, $oids);
235
        }
236
237
        //$this->prtrace('$_REQUEST[query]', $_REQUEST['query']);
238
239
        return $data->conn->Execute($_REQUEST['query']);
240
    }
241
242
    private function _getResponse($format)
243
    {
244
        $response = $this
245
            ->container
246
            ->response;
247
248
        // Make it do a download, if necessary
249
        if ('download' !== $_REQUEST['output']) {
250
            return $response
251
                ->withHeader('Content-type', 'text/plain');
252
        }
253
        // Set headers.  MSIE is totally broken for SSL downloading, so
254
        // we need to have it download in-place as plain text
255
        if (\mb_strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE') && isset($_SERVER['HTTPS'])) {
256
            return $response
257
                ->withHeader('Content-type', 'text/plain');
258
        }
259
        $response = $response
260
            ->withHeader('Content-type', 'application/download');
261
262
        $ext = 'txt';
263
264
        if (isset($this->extensions[$format])) {
265
            $ext = $this->extensions[$format];
266
        }
267
268
        return $response
269
            ->withHeader('Content-Disposition', 'attachment; filename=dump.' . $ext);
270
    }
271
272
    private function pickFormat($data, $object, bool $oids, $rs, $format, $response)
273
    {
274
        if ('copy' === $format) {
275
            $this->_mimicCopy($data, $object, $oids, $rs);
276
        } elseif ('html' === $format) {
277
            $response = $response
278
                ->withHeader('Content-type', 'text/html');
279
            $this->_mimicHtml($data, $object, $oids, $rs);
280
        } elseif ('xml' === $format) {
281
            $response = $response
282
                ->withHeader('Content-type', 'application/xml');
283
            $this->_mimicXml($data, $object, $oids, $rs);
284
        } elseif ('sql' === $format) {
285
            $this->_mimicSQL($data, $object, $oids, $rs);
286
        }
287
        $this->_csvOrTab($data, $object, $oids, $rs, $format);
288
289
        return $response;
290
    }
291
292
    private function _mimicCopy($data, $object, $oids, $rs): void
293
    {
294
        $data->fieldClean($object);
295
        echo "COPY \"{$_REQUEST['table']}\"";
296
297
        if ($oids) {
298
            echo ' WITH OIDS';
299
        }
300
301
        echo " FROM stdin;\n";
302
303
        while (!$rs->EOF) {
304
            $first = true;
305
            //while (list($k, $v) = each($rs->fields)) {
306
            foreach ($rs->fields as $k => $v) {
307
                // Escape value
308
                $v = $data->escapeBytea($v);
309
310
                // We add an extra escaping slash onto octal encoded characters
311
                $v = \preg_replace('/\\\\([0-7]{3})/', '\\\\\1', $v);
312
313
                if ($first) {
314
                    echo (null === $v) ? '\\N' : $v;
315
                    $first = false;
316
                } else {
317
                    echo "\t", (null === $v) ? '\\N' : $v;
318
                }
319
            }
320
            echo \PHP_EOL;
321
            $rs->moveNext();
322
        }
323
        echo "\\.\n";
324
    }
325
326
    private function _mimicHtml($data, $object, $oids, $rs): void
327
    {
328
        echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n";
329
        echo "<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n";
330
        echo "<head>\r\n";
331
        echo "\t<title></title>\r\n";
332
        echo "\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n";
333
        echo "</head>\r\n";
334
        echo "<body>\r\n";
335
        echo "<table class=\"phppgadmin\">\r\n";
336
        echo "\t<tr>\r\n";
337
338
        if (!$rs->EOF) {
339
            // Output header row
340
            $j = 0;
341
342
            foreach ($rs->fields as $k => $v) {
343
                $finfo = $rs->fetchField($j++);
344
345
                if ($finfo->name === $data->id && !$oids) {
346
                    continue;
347
                }
348
349
                echo "\t\t<th>", $this->misc->printVal($finfo->name, 'verbatim'), "</th>\r\n";
350
            }
351
        }
352
        echo "\t</tr>\r\n";
353
354
        while (!$rs->EOF) {
355
            echo "\t<tr>\r\n";
356
            $j = 0;
357
358
            foreach ($rs->fields as $k => $v) {
359
                $finfo = $rs->fetchField($j++);
360
361
                if ($finfo->name === $data->id && !$oids) {
362
                    continue;
363
                }
364
365
                echo "\t\t<td>", $this->misc->printVal($v, 'verbatim', $finfo->type), "</td>\r\n";
366
            }
367
            echo "\t</tr>\r\n";
368
            $rs->moveNext();
369
        }
370
        echo "</table>\r\n";
371
        echo "</body>\r\n";
372
        echo "</html>\r\n";
373
    }
374
375
    private function _mimicXml($data, $object, $oids, $rs): void
376
    {
377
        echo '<?xml version="1.0" encoding="utf-8" ?>' . \PHP_EOL;
378
        echo '<data>' . \PHP_EOL;
379
380
        if (!$rs->EOF) {
381
            // Output header row
382
            $j = 0;
383
            echo "\t<header>" . \PHP_EOL;
384
385
            foreach ($rs->fields as $k => $v) {
386
                $finfo = $rs->fetchField($j++);
387
                $name = \htmlspecialchars($finfo->name);
388
                $type = \htmlspecialchars($finfo->type);
389
                echo "\t\t<column name=\"{$name}\" type=\"{$type}\" />" . \PHP_EOL;
390
            }
391
            echo "\t</header>" . \PHP_EOL;
392
        }
393
        echo "\t<records>" . \PHP_EOL;
394
395
        while (!$rs->EOF) {
396
            $j = 0;
397
            echo "\t\t<row>" . \PHP_EOL;
398
399
            foreach ($rs->fields as $k => $v) {
400
                $finfo = $rs->fetchField($j++);
401
                $name = \htmlspecialchars($finfo->name);
402
403
                if (null !== $v) {
404
                    $v = \htmlspecialchars($v);
405
                }
406
407
                echo "\t\t\t<column name=\"{$name}\"", (null === $v ? ' null="null"' : ''), ">{$v}</column>" . \PHP_EOL;
408
            }
409
            echo "\t\t</row>" . \PHP_EOL;
410
            $rs->moveNext();
411
        }
412
        echo "\t</records>" . \PHP_EOL;
413
        echo '</data>' . \PHP_EOL;
414
    }
415
416
    private function _mimicSQL($data, $object, $oids, $rs): void
417
    {
418
        $data->fieldClean($object);
419
        $values = '';
420
421
        while (!$rs->EOF) {
422
            echo "INSERT INTO \"{$object}\" (";
423
            $first = true;
424
            $j = 0;
425
426
            foreach ($rs->fields as $k => $v) {
427
                $finfo = $rs->fetchField($j++);
428
                $k = $finfo->name;
429
                // SQL (INSERT) format cannot handle oids
430
                //                        if ($k == $data->id) continue;
431
                // Output field
432
                $data->fieldClean($k);
433
434
                if ($first) {
435
                    echo "\"{$k}\"";
436
                } else {
437
                    echo ", \"{$k}\"";
438
                }
439
440
                if (null !== $v) {
441
                    // Output value
442
                    // addCSlashes converts all weird ASCII characters to octal representation,
443
                    // EXCEPT the 'special' ones like \r \n \t, etc.
444
                    $v = \addcslashes($v, "\0..\37\177..\377");
445
                    // We add an extra escaping slash onto octal encoded characters
446
                    $v = \preg_replace('/\\\\([0-7]{3})/', '\\\1', $v);
447
                    // Finally, escape all apostrophes
448
                    $v = \str_replace("'", "''", $v);
449
                }
450
451
                if ($first) {
452
                    $values = (null === $v ? 'NULL' : "'{$v}'");
453
                    $first = false;
454
                } else {
455
                    $values .= ', ' . ((null === $v ? 'NULL' : "'{$v}'"));
456
                }
457
            }
458
            echo ") VALUES ({$values});\n";
459
            $rs->moveNext();
460
        }
461
    }
462
463
    private function _csvOrTab($data, $object, $oids, $rs, $format): void
464
    {
465
        switch ($format) {
466
            case 'tab':
467
                $sep = "\t";
468
469
                break;
470
            case 'csv':
471
            default:
472
                $sep = ',';
473
474
                break;
475
        }
476
477
        if (!$rs->EOF) {
478
            // Output header row
479
            $first = true;
480
481
            foreach ($rs->fields as $k => $v) {
482
                $finfo = $rs->fetchField($k);
483
                $v = $finfo->name;
484
485
                if (null !== $v) {
486
                    $v = \str_replace('"', '""', $v);
487
                }
488
489
                if ($first) {
490
                    echo "\"{$v}\"";
491
                    $first = false;
492
                } else {
493
                    echo "{$sep}\"{$v}\"";
494
                }
495
            }
496
            echo "\r\n";
497
        }
498
499
        while (!$rs->EOF) {
500
            $first = true;
501
502
            foreach ($rs->fields as $k => $v) {
503
                if (null !== $v) {
504
                    $v = \str_replace('"', '""', $v);
505
                }
506
507
                if ($first) {
508
                    echo (null === $v) ? '"\\N"' : "\"{$v}\"";
509
                    $first = false;
510
                } else {
511
                    echo null === $v ? "{$sep}\"\\N\"" : "{$sep}\"{$v}\"";
512
                }
513
            }
514
            echo "\r\n";
515
            $rs->moveNext();
516
        }
517
    }
518
}
519