2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Main export handling code
8 declare(strict_types
=1);
11 use PhpMyAdmin\DatabaseInterface
;
12 use PhpMyAdmin\Encoding
;
13 use PhpMyAdmin\Export
;
14 use PhpMyAdmin\Plugins
;
15 use PhpMyAdmin\Plugins\ExportPlugin
;
16 use PhpMyAdmin\Relation
;
17 use PhpMyAdmin\Response
;
18 use PhpMyAdmin\Sanitize
;
19 use PhpMyAdmin\SqlParser\Parser
;
20 use PhpMyAdmin\SqlParser\Statements\SelectStatement
;
21 use PhpMyAdmin\SqlParser\Utils\Misc
;
25 if (! defined('ROOT_PATH')) {
26 define('ROOT_PATH', __DIR__
. DIRECTORY_SEPARATOR
);
29 global $db, $sql_query;
31 include_once ROOT_PATH
. 'libraries/common.inc.php';
33 /** @var Response $response */
34 $response = $containerBuilder->get(Response
::class);
36 /** @var DatabaseInterface $dbi */
37 $dbi = $containerBuilder->get(DatabaseInterface
::class);
39 $header = $response->getHeader();
40 $scripts = $header->getScripts();
41 $scripts->addFile('export_output.js');
43 /** @var Export $export */
44 $export = $containerBuilder->get('export');
46 //check if it's the GET request to check export time out
47 if (isset($_GET['check_time_out'])) {
48 if (isset($_SESSION['pma_export_error'])) {
49 $err = $_SESSION['pma_export_error'];
50 unset($_SESSION['pma_export_error']);
59 * Sets globals from $_POST
61 * - Please keep the parameters in order of their appearance in the form
62 * - Some of these parameters are not used, as the code below directly
63 * verifies from the superglobal $_POST or $_REQUEST
64 * TODO: this should be removed to avoid passing user input to GLOBALS
92 'htmlword_structure_or_data',
96 'mediawiki_structure_or_data',
98 'pdf_structure_or_data',
99 'odt_structure_or_data',
105 'codegen_structure_or_data',
111 'excel_structure_or_data',
112 'yaml_structure_or_data',
114 'ods_structure_or_data',
116 'json_structure_or_data',
119 'xml_structure_or_data',
121 'xml_export_functions',
122 'xml_export_procedures',
124 'xml_export_triggers',
126 'xml_export_contents',
127 'texytext_structure_or_data',
130 'phparray_structure_or_data',
131 'sql_include_comments',
132 'sql_header_comment',
136 'sql_use_transaction',
139 'sql_structure_or_data',
140 'sql_create_database',
142 'sql_procedure_function',
145 'sql_create_trigger',
146 'sql_view_current_user',
148 'sql_or_replace_view',
149 'sql_auto_increment',
156 'sql_max_query_size',
157 'sql_hex_for_binary',
160 'sql_views_as_tables',
169 'csv_structure_or_data',
170 // csv_replace should have been here but we use it directly from $_POST
172 'latex_structure_or_data',
173 'latex_structure_caption',
174 'latex_structure_continued_caption',
175 'latex_structure_label',
180 'latex_data_caption',
181 'latex_data_continued_caption',
187 foreach ($post_params as $one_post_param) {
188 if (isset($_POST[$one_post_param])) {
189 $GLOBALS[$one_post_param] = $_POST[$one_post_param];
193 $table = $GLOBALS['table'];
195 PhpMyAdmin\Util
::checkParameters(['what', 'export_type']);
197 // sanitize this parameter which will be used below in a file inclusion
198 $what = Core
::securePath($_POST['what']);
200 // export class instance, not array of properties, as before
201 /** @var ExportPlugin $export_plugin */
202 $export_plugin = Plugins
::getPlugin(
205 'libraries/classes/Plugins/Export/',
207 'export_type' => $export_type,
208 'single_table' => isset($single_table),
213 if (empty($export_plugin)) {
214 Core
::fatalError(__('Bad type!'));
218 * valid compression methods
220 $compression_methods = [
226 * init and variable checking
230 $save_on_server = false;
231 $buffer_needed = false;
238 $separate_files = '';
240 // Is it a quick or custom export?
241 if (isset($_POST['quick_or_custom'])
242 && $_POST['quick_or_custom'] == 'quick'
244 $quick_export = true;
246 $quick_export = false;
249 if ($_POST['output_format'] == 'astext') {
253 if (isset($_POST['as_separate_files'])
254 && ! empty($_POST['as_separate_files'])
256 if (isset($_POST['compression'])
257 && ! empty($_POST['compression'])
258 && $_POST['compression'] == 'zip'
260 $separate_files = $_POST['as_separate_files'];
263 if (in_array($_POST['compression'], $compression_methods)) {
264 $compression = $_POST['compression'];
265 $buffer_needed = true;
267 if (($quick_export && ! empty($_POST['quick_export_onserver']))
268 ||
(! $quick_export && ! empty($_POST['onserver']))
271 $onserver = $_POST['quick_export_onserver'];
273 $onserver = $_POST['onserver'];
275 // Will we save dump on server?
276 $save_on_server = ! empty($cfg['SaveDir']) && $onserver;
281 * If we are sending the export file (as opposed to just displaying it
282 * as text), we have to bypass the usual PhpMyAdmin\Response mechanism
284 if (isset($_POST['output_format']) && $_POST['output_format'] == 'sendit' && ! $save_on_server) {
285 $response->disable();
286 //Disable all active buffers (see: ob_get_status(true) at this point)
288 if (ob_get_length() > 0 ||
ob_get_level() > 0) {
289 $hasBuffer = ob_end_clean();
293 } while ($hasBuffer);
297 // Generate error url and check for needed variables
298 if ($export_type == 'server') {
299 $err_url = 'server_export.php' . Url
::getCommon();
300 } elseif ($export_type == 'database' && strlen($db) > 0) {
301 $err_url = 'db_export.php' . Url
::getCommon(['db' => $db]);
302 // Check if we have something to export
303 if (isset($table_select)) {
304 $tables = $table_select;
308 } elseif ($export_type == 'table' && strlen($db) > 0 && strlen($table) > 0) {
309 $err_url = 'tbl_export.php' . Url
::getCommon(
316 Core
::fatalError(__('Bad parameters!'));
319 // Merge SQL Query aliases with Export aliases from
320 // export page, Export page aliases are given more
321 // preference over SQL Query aliases.
322 $parser = new Parser($sql_query);
324 if (! empty($parser->statements
[0])
325 && ($parser->statements
[0] instanceof SelectStatement
)
327 $aliases = Misc
::getAliases($parser->statements
[0], $db);
329 if (! empty($_POST['aliases'])) {
330 $aliases = $export->mergeAliases($aliases, $_POST['aliases']);
331 $_SESSION['tmpval']['aliases'] = $_POST['aliases'];
335 * Increase time limit for script execution and initializes some variables
337 Util
::setTimeLimit();
338 if (! empty($cfg['MemoryLimit'])) {
339 ini_set('memory_limit', $cfg['MemoryLimit']);
341 register_shutdown_function([$export, 'shutdown']);
342 // Start with empty buffer
344 $dump_buffer_len = 0;
346 // Array of dump_buffers - used in separate file exports
347 $dump_buffer_objects = [];
349 // We send fake headers to avoid browser timeout when buffering
350 $time_start = time();
352 // Defines the default <CR><LF> format.
353 // For SQL always use \n as MySQL wants this on all platforms.
354 if ($what == 'sql') {
360 $output_kanji_conversion = Encoding
::canConvertKanji();
362 // Do we need to convert charset?
363 $output_charset_conversion = $asfile
364 && Encoding
::isSupported()
365 && isset($charset) && $charset != 'utf-8';
367 // Use on the fly compression?
368 $GLOBALS['onfly_compression'] = $GLOBALS['cfg']['CompressOnFly']
369 && $compression == 'gzip';
370 if ($GLOBALS['onfly_compression']) {
371 $GLOBALS['memory_limit'] = $export->getMemoryLimit();
374 // Generate filename and mime type if needed
376 if (empty($remember_template)) {
377 $remember_template = '';
379 list($filename, $mime_type) = $export->getFilenameAndMimetype(
390 // Open file on server if needed
391 if ($save_on_server) {
392 list($save_filename, $message, $file_handle) = $export->openFile(
397 // problem opening export file on server?
398 if (! empty($message)) {
399 $export->showPage($db, $table, $export_type);
403 * Send headers depending on whether the user chose to download a dump file
408 // (avoid rewriting data containing HTML with anchors and forms;
409 // this was reported to happen under Plesk)
410 ini_set('url_rewriter.tags', '');
411 $filename = Sanitize
::sanitizeFilename($filename);
413 Core
::downloadHeader($filename, $mime_type);
416 if ($export_type == 'database') {
417 $num_tables = count($tables);
418 if ($num_tables === 0) {
419 $message = PhpMyAdmin\Message
::error(
420 __('No tables found in database.')
422 $active_page = 'db_export.php';
423 include ROOT_PATH
. 'db_export.php';
427 list($html, $back_button, $refreshButton) = $export->getHtmlForDisplayedExportHeader(
437 /** @var Relation $relation */
438 $relation = $containerBuilder->get('relation');
440 // Fake loop just to allow skip of remain of this code by break, I'd really
441 // need exceptions here :-)
445 $dump_buffer_len = 0;
447 // Add possibly some comments to export
448 if (! $export_plugin->exportHeader()) {
452 // Will we need relation & co. setup?
453 $do_relation = isset($GLOBALS[$what . '_relation']);
454 $do_comments = isset($GLOBALS[$what . '_include_comments'])
455 ||
isset($GLOBALS[$what . '_comments']);
456 $do_mime = isset($GLOBALS[$what . '_mime']);
457 if ($do_relation ||
$do_comments ||
$do_mime) {
458 $cfgRelation = $relation->getRelationsParam();
461 // Include dates in export?
462 $do_dates = isset($GLOBALS[$what . '_dates']);
464 $whatStrucOrData = $GLOBALS[$what . '_structure_or_data'];
469 if ($export_type == 'server') {
470 if (! isset($db_select)) {
473 $export->exportServer(
487 } elseif ($export_type == 'database') {
488 if (! isset($table_structure) ||
! is_array($table_structure)) {
489 $table_structure = [];
491 if (! isset($table_data) ||
! is_array($table_data)) {
494 if (! empty($_POST['structure_or_data_forced'])) {
495 $table_structure = $tables;
496 $table_data = $tables;
498 if (isset($lock_tables)) {
499 $export->lockTables($db, $tables, "READ");
501 $export->exportDatabase(
519 $export->unlockTables();
522 $export->exportDatabase(
541 // We export just one table
542 // $allrows comes from the form when "Dump all rows" has been selected
543 if (! isset($allrows)) {
546 if (! isset($limit_to)) {
549 if (! isset($limit_from)) {
552 if (isset($lock_tables)) {
554 $export->lockTables($db, [$table], "READ");
555 $export->exportTable(
574 $export->unlockTables();
577 $export->exportTable(
597 if (! $export_plugin->exportFooter()) {
603 if ($save_on_server && ! empty($message)) {
604 $export->showPage($db, $table, $export_type);
608 * Send the dump as a file...
610 if (empty($asfile)) {
611 echo $export->getHtmlForDisplayedExportFooter($back_button, $refreshButton);
615 // Convert the charset if required.
616 if ($output_charset_conversion) {
617 $dump_buffer = Encoding
::convertString(
624 // Compression needed?
626 if (! empty($separate_files)) {
627 $dump_buffer = $export->compress(
628 $dump_buffer_objects,
633 $dump_buffer = $export->compress($dump_buffer, $compression, $filename);
637 /* If we saved on server, we have to close file now */
638 if ($save_on_server) {
639 $message = $export->closeFile(
644 $export->showPage($db, $table, $export_type);