Passed
Push — master ( 8e7bd8...845e94 )
by Maurício
07:40
created

export.php (1 issue)

1
<?php
2
/* vim: set expandtab sw=4 ts=4 sts=4: */
3
/**
4
 * Main export handling code
5
 *
6
 * @package PhpMyAdmin
7
 */
8
declare(strict_types=1);
9
10
use PhpMyAdmin\Core;
11
use PhpMyAdmin\Encoding;
12
use PhpMyAdmin\Export;
13
use PhpMyAdmin\Plugins;
14
use PhpMyAdmin\Plugins\ExportPlugin;
15
use PhpMyAdmin\Relation;
16
use PhpMyAdmin\Sanitize;
17
use PhpMyAdmin\Url;
18
use PhpMyAdmin\Util;
19
use PhpMyAdmin\Response;
20
21
if (! defined('ROOT_PATH')) {
22
    define('ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR);
23
}
24
25
/**
26
 * Get the variables sent or posted to this script and a core script
27
 */
28
include_once ROOT_PATH . 'libraries/common.inc.php';
29
30
$response = Response::getInstance();
31
$header   = $response->getHeader();
32
$scripts  = $header->getScripts();
33
$scripts->addFile('export_output.js');
34
35
$export = new Export();
36
37
//check if it's the GET request to check export time out
38
if (isset($_GET['check_time_out'])) {
39
    if (isset($_SESSION['pma_export_error'])) {
40
        $err = $_SESSION['pma_export_error'];
41
        unset($_SESSION['pma_export_error']);
42
        echo "timeout";
43
    } else {
44
        echo "success";
45
    }
46
    exit;
47
}
48
49
/**
50
 * Sets globals from $_POST
51
 *
52
 * - Please keep the parameters in order of their appearance in the form
53
 * - Some of these parameters are not used, as the code below directly
54
 *   verifies from the superglobal $_POST or $_REQUEST
55
 * TODO: this should be removed to avoid passing user input to GLOBALS
56
 * without checking
57
 */
58
$post_params = [
59
    'db',
60
    'table',
61
    'what',
62
    'single_table',
63
    'export_type',
64
    'export_method',
65
    'quick_or_custom',
66
    'db_select',
67
    'table_select',
68
    'table_structure',
69
    'table_data',
70
    'limit_to',
71
    'limit_from',
72
    'allrows',
73
    'lock_tables',
74
    'output_format',
75
    'filename_template',
76
    'maxsize',
77
    'remember_template',
78
    'charset',
79
    'compression',
80
    'as_separate_files',
81
    'knjenc',
82
    'xkana',
83
    'htmlword_structure_or_data',
84
    'htmlword_null',
85
    'htmlword_columns',
86
    'mediawiki_headers',
87
    'mediawiki_structure_or_data',
88
    'mediawiki_caption',
89
    'pdf_structure_or_data',
90
    'odt_structure_or_data',
91
    'odt_relation',
92
    'odt_comments',
93
    'odt_mime',
94
    'odt_columns',
95
    'odt_null',
96
    'codegen_structure_or_data',
97
    'codegen_format',
98
    'excel_null',
99
    'excel_removeCRLF',
100
    'excel_columns',
101
    'excel_edition',
102
    'excel_structure_or_data',
103
    'yaml_structure_or_data',
104
    'ods_null',
105
    'ods_structure_or_data',
106
    'ods_columns',
107
    'json_structure_or_data',
108
    'json_pretty_print',
109
    'json_unicode',
110
    'xml_structure_or_data',
111
    'xml_export_events',
112
    'xml_export_functions',
113
    'xml_export_procedures',
114
    'xml_export_tables',
115
    'xml_export_triggers',
116
    'xml_export_views',
117
    'xml_export_contents',
118
    'texytext_structure_or_data',
119
    'texytext_columns',
120
    'texytext_null',
121
    'phparray_structure_or_data',
122
    'sql_include_comments',
123
    'sql_header_comment',
124
    'sql_dates',
125
    'sql_relation',
126
    'sql_mime',
127
    'sql_use_transaction',
128
    'sql_disable_fk',
129
    'sql_compatibility',
130
    'sql_structure_or_data',
131
    'sql_create_database',
132
    'sql_drop_table',
133
    'sql_procedure_function',
134
    'sql_create_table',
135
    'sql_create_view',
136
    'sql_create_trigger',
137
    'sql_view_current_user',
138
    'sql_if_not_exists',
139
    'sql_or_replace_view',
140
    'sql_auto_increment',
141
    'sql_backquotes',
142
    'sql_truncate',
143
    'sql_delayed',
144
    'sql_ignore',
145
    'sql_type',
146
    'sql_insert_syntax',
147
    'sql_max_query_size',
148
    'sql_hex_for_binary',
149
    'sql_utc_time',
150
    'sql_drop_database',
151
    'sql_views_as_tables',
152
    'sql_metadata',
153
    'csv_separator',
154
    'csv_enclosed',
155
    'csv_escaped',
156
    'csv_terminated',
157
    'csv_null',
158
    'csv_removeCRLF',
159
    'csv_columns',
160
    'csv_structure_or_data',
161
    // csv_replace should have been here but we use it directly from $_POST
162
    'latex_caption',
163
    'latex_structure_or_data',
164
    'latex_structure_caption',
165
    'latex_structure_continued_caption',
166
    'latex_structure_label',
167
    'latex_relation',
168
    'latex_comments',
169
    'latex_mime',
170
    'latex_columns',
171
    'latex_data_caption',
172
    'latex_data_continued_caption',
173
    'latex_data_label',
174
    'latex_null',
175
    'aliases',
176
];
177
178
foreach ($post_params as $one_post_param) {
179
    if (isset($_POST[$one_post_param])) {
180
        $GLOBALS[$one_post_param] = $_POST[$one_post_param];
181
    }
182
}
183
184
$table = $GLOBALS['table'];
185
186
PhpMyAdmin\Util::checkParameters(['what', 'export_type']);
187
188
// sanitize this parameter which will be used below in a file inclusion
189
$what = Core::securePath($_POST['what']);
190
191
// export class instance, not array of properties, as before
192
/** @var ExportPlugin $export_plugin */
193
$export_plugin = Plugins::getPlugin(
194
    "export",
195
    $what,
196
    'libraries/classes/Plugins/Export/',
197
    [
198
        'export_type' => $export_type,
199
        'single_table' => isset($single_table),
200
    ]
201
);
202
203
// Check export type
204
if (empty($export_plugin)) {
205
    Core::fatalError(__('Bad type!'));
206
}
207
208
/**
209
 * valid compression methods
210
 */
211
$compression_methods = [
212
    'zip',
213
    'gzip',
214
];
215
216
/**
217
 * init and variable checking
218
 */
219
$compression = '';
220
$onserver = false;
221
$save_on_server = false;
222
$buffer_needed = false;
223
$back_button = '';
224
$refreshButton = '';
225
$save_filename = '';
226
$file_handle = '';
227
$err_url = '';
228
$filename = '';
229
$separate_files = '';
230
231
// Is it a quick or custom export?
232
if (isset($_POST['quick_or_custom'])
233
    && $_POST['quick_or_custom'] == 'quick'
234
) {
235
    $quick_export = true;
236
} else {
237
    $quick_export = false;
238
}
239
240
if ($_POST['output_format'] == 'astext') {
241
    $asfile = false;
242
} else {
243
    $asfile = true;
244
    if (isset($_POST['as_separate_files'])
245
        && ! empty($_POST['as_separate_files'])
246
    ) {
247
        if (isset($_POST['compression'])
248
            && ! empty($_POST['compression'])
249
            && $_POST['compression'] == 'zip'
250
        ) {
251
            $separate_files = $_POST['as_separate_files'];
252
        }
253
    }
254
    if (in_array($_POST['compression'], $compression_methods)) {
255
        $compression = $_POST['compression'];
256
        $buffer_needed = true;
257
    }
258
    if (($quick_export && ! empty($_POST['quick_export_onserver']))
259
        || (! $quick_export && ! empty($_POST['onserver']))
260
    ) {
261
        if ($quick_export) {
262
            $onserver = $_POST['quick_export_onserver'];
263
        } else {
264
            $onserver = $_POST['onserver'];
265
        }
266
        // Will we save dump on server?
267
        $save_on_server = ! empty($cfg['SaveDir']) && $onserver;
268
    }
269
}
270
271
/**
272
 * If we are sending the export file (as opposed to just displaying it
273
 * as text), we have to bypass the usual PhpMyAdmin\Response mechanism
274
 */
275
if (isset($_POST['output_format']) && $_POST['output_format'] == 'sendit' && ! $save_on_server) {
276
    $response->disable();
277
    //Disable all active buffers (see: ob_get_status(true) at this point)
278
    while (@ob_end_clean());
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
279
}
280
281
$tables = [];
282
// Generate error url and check for needed variables
283
if ($export_type == 'server') {
284
    $err_url = 'server_export.php' . Url::getCommon();
285
} elseif ($export_type == 'database' && strlen($db) > 0) {
286
    $err_url = 'db_export.php' . Url::getCommon(['db' => $db]);
287
    // Check if we have something to export
288
    if (isset($table_select)) {
289
        $tables = $table_select;
290
    } else {
291
        $tables = [];
292
    }
293
} elseif ($export_type == 'table' && strlen($db) > 0 && strlen($table) > 0) {
294
    $err_url = 'tbl_export.php' . Url::getCommon(
295
        [
296
            'db' => $db,
297
            'table' => $table,
298
        ]
299
    );
300
} else {
301
    Core::fatalError(__('Bad parameters!'));
302
}
303
304
// Merge SQL Query aliases with Export aliases from
305
// export page, Export page aliases are given more
306
// preference over SQL Query aliases.
307
$parser = new \PhpMyAdmin\SqlParser\Parser($sql_query);
308
$aliases = [];
309
if (! empty($parser->statements[0])
310
    && ($parser->statements[0] instanceof \PhpMyAdmin\SqlParser\Statements\SelectStatement)
311
) {
312
    $aliases = \PhpMyAdmin\SqlParser\Utils\Misc::getAliases($parser->statements[0], $db);
313
}
314
if (! empty($_POST['aliases'])) {
315
    $aliases = $export->mergeAliases($aliases, $_POST['aliases']);
316
    $_SESSION['tmpval']['aliases'] = $_POST['aliases'];
317
}
318
319
/**
320
 * Increase time limit for script execution and initializes some variables
321
 */
322
Util::setTimeLimit();
323
if (! empty($cfg['MemoryLimit'])) {
324
    ini_set('memory_limit', $cfg['MemoryLimit']);
325
}
326
register_shutdown_function([$export, 'shutdown']);
327
// Start with empty buffer
328
$dump_buffer = '';
329
$dump_buffer_len = 0;
330
331
// Array of dump_buffers - used in separate file exports
332
$dump_buffer_objects = [];
333
334
// We send fake headers to avoid browser timeout when buffering
335
$time_start = time();
336
337
// Defines the default <CR><LF> format.
338
// For SQL always use \n as MySQL wants this on all platforms.
339
if ($what == 'sql') {
340
    $crlf = "\n";
341
} else {
342
    $crlf = PHP_EOL;
343
}
344
345
$output_kanji_conversion = Encoding::canConvertKanji();
346
347
// Do we need to convert charset?
348
$output_charset_conversion = $asfile
349
    && Encoding::isSupported()
350
    && isset($charset) && $charset != 'utf-8';
351
352
// Use on the fly compression?
353
$GLOBALS['onfly_compression'] = $GLOBALS['cfg']['CompressOnFly']
354
    && $compression == 'gzip';
355
if ($GLOBALS['onfly_compression']) {
356
    $GLOBALS['memory_limit'] = $export->getMemoryLimit();
357
}
358
359
// Generate filename and mime type if needed
360
if ($asfile) {
361
    if (empty($remember_template)) {
362
        $remember_template = '';
363
    }
364
    list($filename, $mime_type) = $export->getFilenameAndMimetype(
365
        $export_type,
366
        $remember_template,
367
        $export_plugin,
368
        $compression,
369
        $filename_template
370
    );
371
} else {
372
    $mime_type = '';
373
}
374
375
// Open file on server if needed
376
if ($save_on_server) {
377
    list($save_filename, $message, $file_handle) = $export->openFile(
378
        $filename,
379
        $quick_export
380
    );
381
382
    // problem opening export file on server?
383
    if (! empty($message)) {
384
        $export->showPage($db, $table, $export_type);
385
    }
386
} else {
387
    /**
388
     * Send headers depending on whether the user chose to download a dump file
389
     * or not
390
     */
391
    if ($asfile) {
392
        // Download
393
        // (avoid rewriting data containing HTML with anchors and forms;
394
        // this was reported to happen under Plesk)
395
        ini_set('url_rewriter.tags', '');
396
        $filename = Sanitize::sanitizeFilename($filename);
397
398
        Core::downloadHeader($filename, $mime_type);
399
    } else {
400
        // HTML
401
        if ($export_type == 'database') {
402
            $num_tables = count($tables);
403
            if ($num_tables == 0) {
404
                $message = PhpMyAdmin\Message::error(
405
                    __('No tables found in database.')
406
                );
407
                $active_page = 'db_export.php';
408
                include ROOT_PATH . 'db_export.php';
409
                exit();
410
            }
411
        }
412
        list($html, $back_button, $refreshButton) = $export->getHtmlForDisplayedExportHeader(
413
            $export_type,
414
            $db,
415
            $table
416
        );
417
        echo $html;
418
        unset($html);
419
    } // end download
420
}
421
422
$relation = new Relation($GLOBALS['dbi']);
423
424
// Fake loop just to allow skip of remain of this code by break, I'd really
425
// need exceptions here :-)
426
do {
427
    // Re - initialize
428
    $dump_buffer = '';
429
    $dump_buffer_len = 0;
430
431
    // Add possibly some comments to export
432
    if (! $export_plugin->exportHeader()) {
433
        break;
434
    }
435
436
    // Will we need relation & co. setup?
437
    $do_relation = isset($GLOBALS[$what . '_relation']);
438
    $do_comments = isset($GLOBALS[$what . '_include_comments'])
439
        || isset($GLOBALS[$what . '_comments']);
440
    $do_mime     = isset($GLOBALS[$what . '_mime']);
441
    if ($do_relation || $do_comments || $do_mime) {
442
        $cfgRelation = $relation->getRelationsParam();
443
    }
444
445
    // Include dates in export?
446
    $do_dates = isset($GLOBALS[$what . '_dates']);
447
448
    $whatStrucOrData = $GLOBALS[$what . '_structure_or_data'];
449
450
    /**
451
     * Builds the dump
452
     */
453
    if ($export_type == 'server') {
454
        if (! isset($db_select)) {
455
            $db_select = '';
456
        }
457
        $export->exportServer(
458
            $db_select,
459
            $whatStrucOrData,
460
            $export_plugin,
461
            $crlf,
462
            $err_url,
463
            $export_type,
464
            $do_relation,
465
            $do_comments,
466
            $do_mime,
467
            $do_dates,
468
            $aliases,
469
            $separate_files
470
        );
471
    } elseif ($export_type == 'database') {
472
        if (! isset($table_structure) || ! is_array($table_structure)) {
473
            $table_structure = [];
474
        }
475
        if (! isset($table_data) || ! is_array($table_data)) {
476
            $table_data = [];
477
        }
478
        if (! empty($_POST['structure_or_data_forced'])) {
479
            $table_structure = $tables;
480
            $table_data = $tables;
481
        }
482
        if (isset($lock_tables)) {
483
            $export->lockTables($db, $tables, "READ");
484
            try {
485
                $export->exportDatabase(
486
                    $db,
487
                    $tables,
488
                    $whatStrucOrData,
489
                    $table_structure,
490
                    $table_data,
491
                    $export_plugin,
492
                    $crlf,
493
                    $err_url,
494
                    $export_type,
495
                    $do_relation,
496
                    $do_comments,
497
                    $do_mime,
498
                    $do_dates,
499
                    $aliases,
500
                    $separate_files
501
                );
502
            } finally {
503
                $export->unlockTables();
504
            }
505
        } else {
506
            $export->exportDatabase(
507
                $db,
508
                $tables,
509
                $whatStrucOrData,
510
                $table_structure,
511
                $table_data,
512
                $export_plugin,
513
                $crlf,
514
                $err_url,
515
                $export_type,
516
                $do_relation,
517
                $do_comments,
518
                $do_mime,
519
                $do_dates,
520
                $aliases,
521
                $separate_files
522
            );
523
        }
524
    } else {
525
        // We export just one table
526
        // $allrows comes from the form when "Dump all rows" has been selected
527
        if (! isset($allrows)) {
528
            $allrows = '';
529
        }
530
        if (! isset($limit_to)) {
531
            $limit_to = '0';
532
        }
533
        if (! isset($limit_from)) {
534
            $limit_from = '0';
535
        }
536
        if (isset($lock_tables)) {
537
            try {
538
                $export->lockTables($db, [$table], "READ");
539
                $export->exportTable(
540
                    $db,
541
                    $table,
542
                    $whatStrucOrData,
543
                    $export_plugin,
544
                    $crlf,
545
                    $err_url,
546
                    $export_type,
547
                    $do_relation,
548
                    $do_comments,
549
                    $do_mime,
550
                    $do_dates,
551
                    $allrows,
552
                    $limit_to,
553
                    $limit_from,
554
                    $sql_query,
555
                    $aliases
556
                );
557
            } finally {
558
                $export->unlockTables();
559
            }
560
        } else {
561
            $export->exportTable(
562
                $db,
563
                $table,
564
                $whatStrucOrData,
565
                $export_plugin,
566
                $crlf,
567
                $err_url,
568
                $export_type,
569
                $do_relation,
570
                $do_comments,
571
                $do_mime,
572
                $do_dates,
573
                $allrows,
574
                $limit_to,
575
                $limit_from,
576
                $sql_query,
577
                $aliases
578
            );
579
        }
580
    }
581
    if (! $export_plugin->exportFooter()) {
582
        break;
583
    }
584
} while (false);
585
// End of fake loop
586
587
if ($save_on_server && ! empty($message)) {
588
    $export->showPage($db, $table, $export_type);
589
}
590
591
/**
592
 * Send the dump as a file...
593
 */
594
if (empty($asfile)) {
595
    echo $export->getHtmlForDisplayedExportFooter($back_button, $refreshButton);
596
    return;
597
} // end if
598
599
// Convert the charset if required.
600
if ($output_charset_conversion) {
601
    $dump_buffer = Encoding::convertString(
602
        'utf-8',
603
        $GLOBALS['charset'],
604
        $dump_buffer
605
    );
606
}
607
608
// Compression needed?
609
if ($compression) {
610
    if (! empty($separate_files)) {
611
        $dump_buffer = $export->compress(
612
            $dump_buffer_objects,
613
            $compression,
614
            $filename
615
        );
616
    } else {
617
        $dump_buffer = $export->compress($dump_buffer, $compression, $filename);
618
    }
619
}
620
621
/* If we saved on server, we have to close file now */
622
if ($save_on_server) {
623
    $message = $export->closeFile(
624
        $file_handle,
625
        $dump_buffer,
626
        $save_filename
627
    );
628
    $export->showPage($db, $table, $export_type);
629
} else {
630
    echo $dump_buffer;
631
}
632