Translated using Weblate (French)
[phpmyadmin.git] / export.php
blob5aa7519afcbee36d7592ddc94987740e3d99bad2
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Main export handling code
6 * @package PhpMyAdmin
7 */
8 declare(strict_types=1);
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;
21 if (! defined('ROOT_PATH')) {
22 define('ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR);
25 /**
26 * Get the variables sent or posted to this script and a core script
28 include_once ROOT_PATH . 'libraries/common.inc.php';
30 $response = Response::getInstance();
31 $header = $response->getHeader();
32 $scripts = $header->getScripts();
33 $scripts->addFile('export_output.js');
35 $export = new Export();
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";
46 exit;
49 /**
50 * Sets globals from $_POST
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
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',
178 foreach ($post_params as $one_post_param) {
179 if (isset($_POST[$one_post_param])) {
180 $GLOBALS[$one_post_param] = $_POST[$one_post_param];
184 $table = $GLOBALS['table'];
186 PhpMyAdmin\Util::checkParameters(['what', 'export_type']);
188 // sanitize this parameter which will be used below in a file inclusion
189 $what = Core::securePath($_POST['what']);
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/',
198 'export_type' => $export_type,
199 'single_table' => isset($single_table),
203 // Check export type
204 if (empty($export_plugin)) {
205 Core::fatalError(__('Bad type!'));
209 * valid compression methods
211 $compression_methods = [
212 'zip',
213 'gzip',
217 * init and variable checking
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 = '';
231 // Is it a quick or custom export?
232 if (isset($_POST['quick_or_custom'])
233 && $_POST['quick_or_custom'] == 'quick'
235 $quick_export = true;
236 } else {
237 $quick_export = false;
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'])
247 if (isset($_POST['compression'])
248 && ! empty($_POST['compression'])
249 && $_POST['compression'] == 'zip'
251 $separate_files = $_POST['as_separate_files'];
254 if (in_array($_POST['compression'], $compression_methods)) {
255 $compression = $_POST['compression'];
256 $buffer_needed = true;
258 if (($quick_export && ! empty($_POST['quick_export_onserver']))
259 || (! $quick_export && ! empty($_POST['onserver']))
261 if ($quick_export) {
262 $onserver = $_POST['quick_export_onserver'];
263 } else {
264 $onserver = $_POST['onserver'];
266 // Will we save dump on server?
267 $save_on_server = ! empty($cfg['SaveDir']) && $onserver;
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
275 if (isset($_POST['output_format']) && $_POST['output_format'] == 'sendit' && ! $save_on_server) {
276 $response->disable();
279 $tables = [];
280 // Generate error url and check for needed variables
281 if ($export_type == 'server') {
282 $err_url = 'server_export.php' . Url::getCommon();
283 } elseif ($export_type == 'database' && strlen($db) > 0) {
284 $err_url = 'db_export.php' . Url::getCommon(['db' => $db]);
285 // Check if we have something to export
286 if (isset($table_select)) {
287 $tables = $table_select;
288 } else {
289 $tables = [];
291 } elseif ($export_type == 'table' && strlen($db) > 0 && strlen($table) > 0) {
292 $err_url = 'tbl_export.php' . Url::getCommon(
294 'db' => $db,
295 'table' => $table,
298 } else {
299 Core::fatalError(__('Bad parameters!'));
302 // Merge SQL Query aliases with Export aliases from
303 // export page, Export page aliases are given more
304 // preference over SQL Query aliases.
305 $parser = new \PhpMyAdmin\SqlParser\Parser($sql_query);
306 $aliases = [];
307 if (! empty($parser->statements[0])
308 && ($parser->statements[0] instanceof \PhpMyAdmin\SqlParser\Statements\SelectStatement)
310 $aliases = \PhpMyAdmin\SqlParser\Utils\Misc::getAliases($parser->statements[0], $db);
312 if (! empty($_POST['aliases'])) {
313 $aliases = $export->mergeAliases($aliases, $_POST['aliases']);
314 $_SESSION['tmpval']['aliases'] = $_POST['aliases'];
318 * Increase time limit for script execution and initializes some variables
320 Util::setTimeLimit();
321 if (! empty($cfg['MemoryLimit'])) {
322 ini_set('memory_limit', $cfg['MemoryLimit']);
324 register_shutdown_function([$export, 'shutdown']);
325 // Start with empty buffer
326 $dump_buffer = '';
327 $dump_buffer_len = 0;
329 // Array of dump_buffers - used in separate file exports
330 $dump_buffer_objects = [];
332 // We send fake headers to avoid browser timeout when buffering
333 $time_start = time();
335 // Defines the default <CR><LF> format.
336 // For SQL always use \n as MySQL wants this on all platforms.
337 if ($what == 'sql') {
338 $crlf = "\n";
339 } else {
340 $crlf = PHP_EOL;
343 $output_kanji_conversion = Encoding::canConvertKanji();
345 // Do we need to convert charset?
346 $output_charset_conversion = $asfile
347 && Encoding::isSupported()
348 && isset($charset) && $charset != 'utf-8';
350 // Use on the fly compression?
351 $GLOBALS['onfly_compression'] = $GLOBALS['cfg']['CompressOnFly']
352 && $compression == 'gzip';
353 if ($GLOBALS['onfly_compression']) {
354 $GLOBALS['memory_limit'] = $export->getMemoryLimit();
357 // Generate filename and mime type if needed
358 if ($asfile) {
359 if (empty($remember_template)) {
360 $remember_template = '';
362 list($filename, $mime_type) = $export->getFilenameAndMimetype(
363 $export_type,
364 $remember_template,
365 $export_plugin,
366 $compression,
367 $filename_template
369 } else {
370 $mime_type = '';
373 // Open file on server if needed
374 if ($save_on_server) {
375 list($save_filename, $message, $file_handle) = $export->openFile(
376 $filename,
377 $quick_export
380 // problem opening export file on server?
381 if (! empty($message)) {
382 $export->showPage($db, $table, $export_type);
384 } else {
386 * Send headers depending on whether the user chose to download a dump file
387 * or not
389 if ($asfile) {
390 // Download
391 // (avoid rewriting data containing HTML with anchors and forms;
392 // this was reported to happen under Plesk)
393 ini_set('url_rewriter.tags', '');
394 $filename = Sanitize::sanitizeFilename($filename);
396 Core::downloadHeader($filename, $mime_type);
397 } else {
398 // HTML
399 if ($export_type == 'database') {
400 $num_tables = count($tables);
401 if ($num_tables == 0) {
402 $message = PhpMyAdmin\Message::error(
403 __('No tables found in database.')
405 $active_page = 'db_export.php';
406 include ROOT_PATH . 'db_export.php';
407 exit();
410 list($html, $back_button, $refreshButton) = $export->getHtmlForDisplayedExportHeader(
411 $export_type,
412 $db,
413 $table
415 echo $html;
416 unset($html);
417 } // end download
420 $relation = new Relation($GLOBALS['dbi']);
422 // Fake loop just to allow skip of remain of this code by break, I'd really
423 // need exceptions here :-)
424 do {
425 // Re - initialize
426 $dump_buffer = '';
427 $dump_buffer_len = 0;
429 // Add possibly some comments to export
430 if (! $export_plugin->exportHeader()) {
431 break;
434 // Will we need relation & co. setup?
435 $do_relation = isset($GLOBALS[$what . '_relation']);
436 $do_comments = isset($GLOBALS[$what . '_include_comments'])
437 || isset($GLOBALS[$what . '_comments']);
438 $do_mime = isset($GLOBALS[$what . '_mime']);
439 if ($do_relation || $do_comments || $do_mime) {
440 $cfgRelation = $relation->getRelationsParam();
443 // Include dates in export?
444 $do_dates = isset($GLOBALS[$what . '_dates']);
446 $whatStrucOrData = $GLOBALS[$what . '_structure_or_data'];
449 * Builds the dump
451 if ($export_type == 'server') {
452 if (! isset($db_select)) {
453 $db_select = '';
455 $export->exportServer(
456 $db_select,
457 $whatStrucOrData,
458 $export_plugin,
459 $crlf,
460 $err_url,
461 $export_type,
462 $do_relation,
463 $do_comments,
464 $do_mime,
465 $do_dates,
466 $aliases,
467 $separate_files
469 } elseif ($export_type == 'database') {
470 if (! isset($table_structure) || ! is_array($table_structure)) {
471 $table_structure = [];
473 if (! isset($table_data) || ! is_array($table_data)) {
474 $table_data = [];
476 if (! empty($_POST['structure_or_data_forced'])) {
477 $table_structure = $tables;
478 $table_data = $tables;
480 if (isset($lock_tables)) {
481 $export->lockTables($db, $tables, "READ");
482 try {
483 $export->exportDatabase(
484 $db,
485 $tables,
486 $whatStrucOrData,
487 $table_structure,
488 $table_data,
489 $export_plugin,
490 $crlf,
491 $err_url,
492 $export_type,
493 $do_relation,
494 $do_comments,
495 $do_mime,
496 $do_dates,
497 $aliases,
498 $separate_files
500 } finally {
501 $export->unlockTables();
503 } else {
504 $export->exportDatabase(
505 $db,
506 $tables,
507 $whatStrucOrData,
508 $table_structure,
509 $table_data,
510 $export_plugin,
511 $crlf,
512 $err_url,
513 $export_type,
514 $do_relation,
515 $do_comments,
516 $do_mime,
517 $do_dates,
518 $aliases,
519 $separate_files
522 } else {
523 // We export just one table
524 // $allrows comes from the form when "Dump all rows" has been selected
525 if (! isset($allrows)) {
526 $allrows = '';
528 if (! isset($limit_to)) {
529 $limit_to = '0';
531 if (! isset($limit_from)) {
532 $limit_from = '0';
534 if (isset($lock_tables)) {
535 try {
536 $export->lockTables($db, [$table], "READ");
537 $export->exportTable(
538 $db,
539 $table,
540 $whatStrucOrData,
541 $export_plugin,
542 $crlf,
543 $err_url,
544 $export_type,
545 $do_relation,
546 $do_comments,
547 $do_mime,
548 $do_dates,
549 $allrows,
550 $limit_to,
551 $limit_from,
552 $sql_query,
553 $aliases
555 } finally {
556 $export->unlockTables();
558 } else {
559 $export->exportTable(
560 $db,
561 $table,
562 $whatStrucOrData,
563 $export_plugin,
564 $crlf,
565 $err_url,
566 $export_type,
567 $do_relation,
568 $do_comments,
569 $do_mime,
570 $do_dates,
571 $allrows,
572 $limit_to,
573 $limit_from,
574 $sql_query,
575 $aliases
579 if (! $export_plugin->exportFooter()) {
580 break;
582 } while (false);
583 // End of fake loop
585 if ($save_on_server && ! empty($message)) {
586 $export->showPage($db, $table, $export_type);
590 * Send the dump as a file...
592 if (empty($asfile)) {
593 echo $export->getHtmlForDisplayedExportFooter($back_button, $refreshButton);
594 return;
595 } // end if
597 // Convert the charset if required.
598 if ($output_charset_conversion) {
599 $dump_buffer = Encoding::convertString(
600 'utf-8',
601 $GLOBALS['charset'],
602 $dump_buffer
606 // Compression needed?
607 if ($compression) {
608 if (! empty($separate_files)) {
609 $dump_buffer = $export->compress(
610 $dump_buffer_objects,
611 $compression,
612 $filename
614 } else {
615 $dump_buffer = $export->compress($dump_buffer, $compression, $filename);
619 /* If we saved on server, we have to close file now */
620 if ($save_on_server) {
621 $message = $export->closeFile(
622 $file_handle,
623 $dump_buffer,
624 $save_filename
626 $export->showPage($db, $table, $export_type);
627 } else {
628 echo $dump_buffer;