Passed
Pull Request — develop (#212)
by Felipe
05:01
created

DataexportController::_getResponse()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 27
rs 9.4222
c 0
b 0
f 0
cc 5
nc 4
nop 1
1
<?php
2
3
/**
4
 * PHPPgAdmin v6.0.0-beta.49
5
 */
6
7
namespace PHPPgAdmin\Controller;
8
9
/**
10
 * Base controller class.
11
 *
12
 * @package PHPPgAdmin
13
 */
14
class DataexportController extends BaseController
15
{
16
    public $extensions = [
17
        'sql'  => 'sql',
18
        'copy' => 'sql',
19
        'csv'  => 'csv',
20
        'tab'  => 'txt',
21
        'html' => 'html',
22
        'xml'  => 'xml',
23
    ];
24
    public $controller_title = 'strexport';
25
26
    /**
27
     * Default method to render the controller according to the action parameter.
28
     */
29
    public function render()
30
    {
31
        set_time_limit(0);
32
33
        // if (!isset($_REQUEST['table']) && !isset($_REQUEST['query']))
34
        // What must we do in this case? Maybe redirect to the homepage?
35
36
        $format = 'N/A';
37
38
        // force behavior to assume there is no pg_dump in the system
39
        $forcemimic = isset($_REQUEST['forcemimic']) ? $_REQUEST['forcemimic'] : false;
40
41
        // If format is set, then perform the export
42
        if (!isset($_REQUEST['what'])) {
43
            return $this->doDefault();
44
        }
45
46
        $this->prtrace("REQUEST['what']", $_REQUEST['what']);
47
48
        // Include application functions
49
        $this->setNoOutput(true);
50
        $clean = false;
51
        $oids  = false;
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
                $this->prtrace('d_format is', $_REQUEST['d_format'], 'd_oids is', isset($_REQUEST['d_oids']));
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
    protected function mimicDumpFeature($format, $cleanprefix, $oids)
98
    {
99
        $data = $this->misc->getDatabaseAccessor();
100
101
        set_time_limit(0);
102
103
        // if (!isset($_REQUEST['table']) && !isset($_REQUEST['query']))
104
        // What must we do in this case? Maybe redirect to the homepage?
105
106
        // If format is set, then perform the export
107
        if (!isset($_REQUEST['what'])) {
108
            return $this->doDefault();
109
        }
110
111
        $this->prtrace("REQUEST['what']", $_REQUEST['what']);
112
113
        // Include application functions
114
        $this->setNoOutput(true);
115
116
        $response = $this->_getResponse($format);
117
118
        $this->coalesceArr($_REQUEST, 'query', '');
119
120
        $_REQUEST['query'] = trim(urldecode($_REQUEST['query']));
121
122
        // Set the schema search path
123
        if (isset($_REQUEST['search_path'])) {
124
            $data->setSearchPath(array_map('trim', explode(',', $_REQUEST['search_path'])));
125
        } elseif (isset($_REQUEST['schema'])) {
126
            $data->setSearchPath($_REQUEST['schema']);
127
        }
128
129
        $subject = $this->coalesceArr($_REQUEST, 'subject', 'table')['subject'];
130
131
        $object = $this->coalesceArr($_REQUEST, $subject)[$subject];
132
133
        // Set up the dump transaction
134
        $status = $data->beginDump();
135
        $this->prtrace('subject', $subject);
136
        $this->prtrace('object', $object);
137
        $tabledefprefix = '';
138
        $tabledefsuffix = '';
139
140
        // If the dump is not dataonly then dump the structure prefix
141
        if ('dataonly' != $_REQUEST['what']) {
142
            $tabledefprefix = $data->getTableDefPrefix($object, $cleanprefix);
143
            $this->prtrace('tabledefprefix', $tabledefprefix);
144
            echo $tabledefprefix;
145
        }
146
147
        // If the dump is not structureonly then dump the actual data
148
        if ('structureonly' != $_REQUEST['what']) {
149
            // Get database encoding
150
            //$dbEncoding = $data->getDatabaseEncoding();
151
152
            // Set fetch mode to NUM so that duplicate field names are properly returned
153
            $data->conn->setFetchMode(\ADODB_FETCH_NUM);
154
155
            // Execute the query, if set, otherwise grab all rows from the table
156
            $rs = $this->_getRS($data, $object, $oids);
157
158
            $response = $this->pickFormat($data, $object, $oids, $rs, $format, $response);
159
        }
160
        if ('dataonly' != $_REQUEST['what']) {
161
            $data->conn->setFetchMode(\ADODB_FETCH_ASSOC);
162
            $tabledefsuffix = $data->getTableDefSuffix($object);
163
            $this->prtrace('tabledefsuffix', $tabledefsuffix);
164
            echo $tabledefsuffix;
165
        }
166
167
        // Finish the dump transaction
168
        $status = $data->endDump();
169
170
        return $response;
171
    }
172
173
    private function _getRS($data, $object, $oids)
174
    {
175
        if ($object) {
176
            return $data->dumpRelation($object, $oids);
177
        }
178
179
        $this->prtrace('$_REQUEST[query]', $_REQUEST['query']);
180
181
        return $data->conn->Execute($_REQUEST['query']);
182
    }
183
184
    private function _getResponse($format)
185
    {
186
        $response = $this
187
            ->container
188
            ->responseobj;
189
190
        // Make it do a download, if necessary
191
        if ('download' !== $_REQUEST['output']) {
192
            return $response
193
                ->withHeader('Content-type', 'text/plain');
194
        }
195
        // Set headers.  MSIE is totally broken for SSL downloading, so
196
        // we need to have it download in-place as plain text
197
        if (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE') && isset($_SERVER['HTTPS'])) {
198
            return $response
199
                ->withHeader('Content-type', 'text/plain');
200
        }
201
        $response = $response
202
            ->withHeader('Content-type', 'application/download');
203
204
        $ext = 'txt';
205
        if (isset($this->extensions[$format])) {
206
            $ext = $this->extensions[$format];
207
        }
208
209
        return $response
210
            ->withHeader('Content-Disposition', 'attachment; filename=dump.'.$ext);
211
    }
212
213
    private function pickFormat($data, $object, $oids, $rs, $format, $response)
214
    {
215
        if ('copy' == $format) {
216
            $this->_mimicCopy($data, $object, $oids, $rs);
217
        } elseif ('html' == $format) {
218
            $response = $response
219
                ->withHeader('Content-type', 'text/html');
220
            $this->_mimicHtml($data, $object, $oids, $rs);
221
        } elseif ('xml' == $format) {
222
            $response = $response
223
                ->withHeader('Content-type', 'application/xml');
224
            $this->_mimicXml($data, $object, $oids, $rs);
225
        } elseif ('sql' == $format) {
226
            $this->_mimicSQL($data, $object, $oids, $rs);
227
        }
228
        $this->_csvOrTab($data, $object, $oids, $rs, $format);
229
230
        return $response;
231
    }
232
233
    public function doDefault($msg = '')
234
    {
235
        if (!isset($_REQUEST['query']) || empty($_REQUEST['query'])) {
236
            $_REQUEST['query'] = $_SESSION['sqlquery'];
237
        }
238
239
        $this->printHeader();
240
        $this->printBody();
241
        $this->printTrail(isset($_REQUEST['subject']) ? $_REQUEST['subject'] : 'database');
242
        $this->printTitle($this->lang['strexport']);
243
        if (isset($msg)) {
244
            $this->printMsg($msg);
245
        }
246
247
        echo '<form action="'.\SUBFOLDER.'/src/views/dataexport" method="post">'.PHP_EOL;
248
        echo '<table>'.PHP_EOL;
249
        echo "<tr><th class=\"data\">{$this->lang['strformat']}:</th><td><select name=\"d_format\">".PHP_EOL;
250
        // COPY and SQL require a table
251
        if (isset($_REQUEST['table'])) {
252
            echo '<option value="copy">COPY</option>'.PHP_EOL;
253
            echo '<option value="sql">SQL</option>'.PHP_EOL;
254
        }
255
        echo '<option value="csv">CSV</option>'.PHP_EOL;
256
        echo "<option value=\"tab\">{$this->lang['strtabbed']}</option>".PHP_EOL;
257
        echo '<option value="html">XHTML</option>'.PHP_EOL;
258
        echo '<option value="xml">XML</option>'.PHP_EOL;
259
        echo '</select></td></tr>';
260
        echo '</table>'.PHP_EOL;
261
262
        echo "<h3>{$this->lang['stroptions']}</h3>".PHP_EOL;
263
        echo "<p><input type=\"radio\" id=\"output1\" name=\"output\" value=\"show\" checked=\"checked\" /><label for=\"output1\">{$this->lang['strshow']}</label>".PHP_EOL;
264
        echo "<br/><input type=\"radio\" id=\"output2\" name=\"output\" value=\"download\" /><label for=\"output2\">{$this->lang['strdownload']}</label></p>".PHP_EOL;
265
266
        echo '<p><input type="hidden" name="action" value="export" />'.PHP_EOL;
267
        echo '<input type="hidden" name="what" value="dataonly" />'.PHP_EOL;
268
        if (isset($_REQUEST['table'])) {
269
            echo '<input type="hidden" name="subject" value="table" />'.PHP_EOL;
270
            echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />'.PHP_EOL;
271
        } else {
272
            echo '<input type="hidden" name="subject" value="table" />'.PHP_EOL;
273
        }
274
        $this->prtrace('$_REQUEST[query]', $_REQUEST['query'], htmlspecialchars(urlencode($_REQUEST['query'])));
275
        $this->prtrace('$_SESSION[sqlquery]', $_SESSION['sqlquery'], htmlspecialchars(urlencode($_SESSION['sqlquery'])));
276
        echo '<input type="hidden" name="query" value="', htmlspecialchars(urlencode($_REQUEST['query'])), '" />'.PHP_EOL;
277
        if (isset($_REQUEST['search_path'])) {
278
            echo '<input type="hidden" name="search_path" value="', htmlspecialchars($_REQUEST['search_path']), '" />'.PHP_EOL;
279
        }
280
        echo $this->misc->form;
281
        echo "<input type=\"submit\" value=\"{$this->lang['strexport']}\" /></p>".PHP_EOL;
282
        echo '</form>'.PHP_EOL;
283
284
        $this->printFooter();
285
    }
286
287
    private function _mimicCopy($data, $object, $oids, $rs)
288
    {
289
        $data->fieldClean($object);
290
        echo "COPY \"{$_REQUEST['table']}\"";
291
        if ($oids) {
292
            echo ' WITH OIDS';
293
        }
294
295
        echo " FROM stdin;\n";
296
        while (!$rs->EOF) {
297
            $first = true;
298
            //while (list($k, $v) = each($rs->fields)) {
299
            foreach ($rs->fields as $k => $v) {
300
                // Escape value
301
                $v = $data->escapeBytea($v);
302
303
                // We add an extra escaping slash onto octal encoded characters
304
                $v = preg_replace('/\\\\([0-7]{3})/', '\\\\\1', $v);
305
                if ($first) {
306
                    echo (is_null($v)) ? '\\N' : $v;
307
                    $first = false;
308
                } else {
309
                    echo "\t", (is_null($v)) ? '\\N' : $v;
310
                }
311
            }
312
            echo PHP_EOL;
313
            $rs->moveNext();
314
        }
315
        echo "\\.\n";
316
    }
317
318
    private function _mimicHtml($data, $object, $oids, $rs)
319
    {
320
        echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n";
321
        echo "<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n";
322
        echo "<head>\r\n";
323
        echo "\t<title></title>\r\n";
324
        echo "\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n";
325
        echo "</head>\r\n";
326
        echo "<body>\r\n";
327
        echo "<table class=\"phppgadmin\">\r\n";
328
        echo "\t<tr>\r\n";
329
        if (!$rs->EOF) {
330
            // Output header row
331
            $j = 0;
332
            foreach ($rs->fields as $k => $v) {
333
                $finfo = $rs->fetchField($j++);
334
                if ($finfo->name == $data->id && !$oids) {
335
                    continue;
336
                }
337
338
                echo "\t\t<th>", $this->misc->printVal($finfo->name, 'verbatim'), "</th>\r\n";
339
            }
340
        }
341
        echo "\t</tr>\r\n";
342
        while (!$rs->EOF) {
343
            echo "\t<tr>\r\n";
344
            $j = 0;
345
            foreach ($rs->fields as $k => $v) {
346
                $finfo = $rs->fetchField($j++);
347
                if ($finfo->name == $data->id && !$oids) {
348
                    continue;
349
                }
350
351
                echo "\t\t<td>", $this->misc->printVal($v, 'verbatim', $finfo->type), "</td>\r\n";
352
            }
353
            echo "\t</tr>\r\n";
354
            $rs->moveNext();
355
        }
356
        echo "</table>\r\n";
357
        echo "</body>\r\n";
358
        echo "</html>\r\n";
359
    }
360
361
    private function _mimicXml($data, $object, $oids, $rs)
362
    {
363
        echo '<?xml version="1.0" encoding="utf-8" ?>'.PHP_EOL;
364
        echo '<data>'.PHP_EOL;
365
        if (!$rs->EOF) {
366
            // Output header row
367
            $j = 0;
368
            echo "\t<header>".PHP_EOL;
369
            foreach ($rs->fields as $k => $v) {
370
                $finfo = $rs->fetchField($j++);
371
                $name  = htmlspecialchars($finfo->name);
372
                $type  = htmlspecialchars($finfo->type);
373
                echo "\t\t<column name=\"{$name}\" type=\"{$type}\" />".PHP_EOL;
374
            }
375
            echo "\t</header>".PHP_EOL;
376
        }
377
        echo "\t<records>".PHP_EOL;
378
        while (!$rs->EOF) {
379
            $j = 0;
380
            echo "\t\t<row>".PHP_EOL;
381
            foreach ($rs->fields as $k => $v) {
382
                $finfo = $rs->fetchField($j++);
383
                $name  = htmlspecialchars($finfo->name);
384
                if (!is_null($v)) {
385
                    $v = htmlspecialchars($v);
386
                }
387
388
                echo "\t\t\t<column name=\"{$name}\"", (is_null($v) ? ' null="null"' : ''), ">{$v}</column>".PHP_EOL;
389
            }
390
            echo "\t\t</row>".PHP_EOL;
391
            $rs->moveNext();
392
        }
393
        echo "\t</records>".PHP_EOL;
394
        echo '</data>'.PHP_EOL;
395
    }
396
397
    private function _mimicSQL($data, $object, $oids, $rs)
398
    {
399
        $data->fieldClean($object);
400
        $values = '';
401
        while (!$rs->EOF) {
402
            echo "INSERT INTO \"{$object}\" (";
403
            $first = true;
404
            $j     = 0;
405
            foreach ($rs->fields as $k => $v) {
406
                $finfo = $rs->fetchField($j++);
407
                $k     = $finfo->name;
408
                // SQL (INSERT) format cannot handle oids
409
                //                        if ($k == $data->id) continue;
410
                // Output field
411
                $data->fieldClean($k);
412
                if ($first) {
413
                    echo "\"{$k}\"";
414
                } else {
415
                    echo ", \"{$k}\"";
416
                }
417
418
                if (!is_null($v)) {
419
                    // Output value
420
                    // addCSlashes converts all weird ASCII characters to octal representation,
421
                    // EXCEPT the 'special' ones like \r \n \t, etc.
422
                    $v = addcslashes($v, "\0..\37\177..\377");
423
                    // We add an extra escaping slash onto octal encoded characters
424
                    $v = preg_replace('/\\\\([0-7]{3})/', '\\\1', $v);
425
                    // Finally, escape all apostrophes
426
                    $v = str_replace("'", "''", $v);
427
                }
428
                if ($first) {
429
                    $values = (is_null($v) ? 'NULL' : "'{$v}'");
430
                    $first  = false;
431
                } else {
432
                    $values .= ', '.((is_null($v) ? 'NULL' : "'{$v}'"));
433
                }
434
            }
435
            echo ") VALUES ({$values});\n";
436
            $rs->moveNext();
437
        }
438
    }
439
440
    private function _csvOrTab($data, $object, $oids, $rs, $format)
441
    {
442
        switch ($format) {
443
            case 'tab':
444
                $sep = "\t";
445
446
                break;
447
            case 'csv':
448
            default:
449
                $sep = ',';
450
451
                break;
452
        }
453
        if (!$rs->EOF) {
454
            // Output header row
455
            $first = true;
456
            foreach ($rs->fields as $k => $v) {
457
                $finfo = $rs->fetchField($k);
458
                $v     = $finfo->name;
459
                if (!is_null($v)) {
460
                    $v = str_replace('"', '""', $v);
461
                }
462
463
                if ($first) {
464
                    echo "\"{$v}\"";
465
                    $first = false;
466
                } else {
467
                    echo "{$sep}\"{$v}\"";
468
                }
469
            }
470
            echo "\r\n";
471
        }
472
        while (!$rs->EOF) {
473
            $first = true;
474
            foreach ($rs->fields as $k => $v) {
475
                if (!is_null($v)) {
476
                    $v = str_replace('"', '""', $v);
477
                }
478
479
                if ($first) {
480
                    echo (is_null($v)) ? '"\\N"' : "\"{$v}\"";
481
                    $first = false;
482
                } else {
483
                    echo is_null($v) ? "{$sep}\"\\N\"" : "{$sep}\"{$v}\"";
484
                }
485
            }
486
            echo "\r\n";
487
            $rs->moveNext();
488
        }
489
    }
490
}
491