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
|
|||
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 |
Adding braces to control structures avoids accidental mistakes as your code changes: