2 /* vim: set expandtab sw=4 ts=4 sts=4: */
4 * Main export handling code
10 * Get the variables sent or posted to this script and a core script
12 require_once 'libraries/common.inc.php';
13 require_once 'libraries/zip.lib.php';
14 require_once 'libraries/plugin_interface.lib.php';
17 * Sets globals from all $_POST (in export.php only)
18 * Would it not be tiresome to list all export-plugin options here?
20 foreach ($_POST as $one_post_param => $one_post_value) {
21 $GLOBALS[$one_post_param] = $one_post_value;
24 PMA_Util
::checkParameters(array('what', 'export_type'));
26 // export class instance, not array of properties, as before
27 $export_plugin = PMA_getPlugin(
30 'libraries/plugins/export/',
32 'export_type' => $export_type,
33 'single_table' => isset($single_table)
37 // Backward compatbility
41 if (! isset($export_plugin)) {
42 PMA_fatalError(__('Bad type!'));
46 * valid compression methods
48 $compression_methods = array(
55 * init and variable checking
59 $save_on_server = false;
60 $buffer_needed = false;
62 // Is it a quick or custom export?
63 if ($_REQUEST['quick_or_custom'] == 'quick') {
66 $quick_export = false;
69 if ($_REQUEST['output_format'] == 'astext') {
73 if (in_array($_REQUEST['compression'], $compression_methods)) {
74 $compression = $_REQUEST['compression'];
75 $buffer_needed = true;
77 if (($quick_export && ! empty($_REQUEST['quick_export_onserver']))
78 ||
(! $quick_export && ! empty($_REQUEST['onserver']))
81 $onserver = $_REQUEST['quick_export_onserver'];
83 $onserver = $_REQUEST['onserver'];
85 // Will we save dump on server?
86 $save_on_server = ! empty($cfg['SaveDir']) && $onserver;
90 // Does export require to be into file?
91 if ($export_plugin->getProperties()->getForceFile() != null && ! $asfile) {
92 $message = PMA_Message
::error(
93 __('Selected export type has to be saved in file!')
95 if ($export_type == 'server') {
96 $active_page = 'server_export.php';
97 include 'server_export.php';
98 } elseif ($export_type == 'database') {
99 $active_page = 'db_export.php';
100 include 'db_export.php';
102 $active_page = 'tbl_export.php';
103 include 'tbl_export.php';
108 // Generate error url and check for needed variables
109 if ($export_type == 'server') {
110 $err_url = 'server_export.php?' . PMA_generate_common_url();
111 } elseif ($export_type == 'database' && strlen($db)) {
112 $err_url = 'db_export.php?' . PMA_generate_common_url($db);
113 // Check if we have something to export
114 if (isset($table_select)) {
115 $tables = $table_select;
119 } elseif ($export_type == 'table' && strlen($db) && strlen($table)) {
120 $err_url = 'tbl_export.php?' . PMA_generate_common_url($db, $table);
122 PMA_fatalError(__('Bad parameters!'));
126 * Increase time limit for script execution and initializes some variables
128 @set_time_limit
($cfg['ExecTimeLimit']);
129 if (! empty($cfg['MemoryLimit'])) {
130 @ini_set
('memory_limit', $cfg['MemoryLimit']);
133 // Start with empty buffer
135 $dump_buffer_len = 0;
137 // We send fake headers to avoid browser timeout when buffering
138 $time_start = time();
142 * Detect ob_gzhandler
146 function PMA_isGzHandlerEnabled()
148 return in_array('ob_gzhandler', ob_list_handlers());
152 * Detect whether gzencode is needed; it might not be needed if
153 * the server is already compressing by itself
155 * @return bool Whether gzencode is needed
157 function PMA_gzencodeNeeded()
159 if (@function_exists
('gzencode')
160 && ! @ini_get
('zlib.output_compression')
161 // Here, we detect Apache's mod_deflate so we bet that
162 // this module is active for this instance of phpMyAdmin
163 // and therefore, will gzip encode the content
164 && ! (function_exists('apache_get_modules')
165 && in_array('mod_deflate', apache_get_modules()))
166 && ! PMA_isGzHandlerEnabled()
175 * Output handler for all exports, if needed buffering, it stores data into
176 * $dump_buffer, otherwise it prints thems out.
178 * @param string $line the insert statement
180 * @return bool Whether output succeeded
182 function PMA_exportOutputHandler($line)
184 global $time_start, $dump_buffer, $dump_buffer_len, $save_filename;
186 // Kanji encoding convert feature
187 if ($GLOBALS['output_kanji_conversion']) {
188 $line = PMA_kanji_str_conv(
191 isset($GLOBALS['xkana']) ?
$GLOBALS['xkana'] : ''
194 // If we have to buffer data, we will perform everything at once at the end
195 if ($GLOBALS['buffer_needed']) {
197 $dump_buffer .= $line;
198 if ($GLOBALS['onfly_compression']) {
200 $dump_buffer_len +
= strlen($line);
202 if ($dump_buffer_len > $GLOBALS['memory_limit']) {
203 if ($GLOBALS['output_charset_conversion']) {
204 $dump_buffer = PMA_convert_string(
206 $GLOBALS['charset_of_file'],
211 if ($GLOBALS['compression'] == 'bzip2'
212 && @function_exists
('bzcompress')
214 $dump_buffer = bzcompress($dump_buffer);
215 } elseif ($GLOBALS['compression'] == 'gzip'
216 && PMA_gzencodeNeeded()
219 // without the optional parameter level because it bugs
220 $dump_buffer = gzencode($dump_buffer);
222 if ($GLOBALS['save_on_server']) {
223 $write_result = @fwrite
($GLOBALS['file_handle'], $dump_buffer);
224 if (! $write_result ||
($write_result != strlen($dump_buffer))) {
225 $GLOBALS['message'] = PMA_Message
::error(
226 __('Insufficient space to save the file %s.')
228 $GLOBALS['message']->addParam($save_filename);
235 $dump_buffer_len = 0;
239 if ($time_start >= $time_now +
30) {
240 $time_start = $time_now;
241 header('X-pmaPing: Pong');
245 if ($GLOBALS['asfile']) {
246 if ($GLOBALS['output_charset_conversion']) {
247 $line = PMA_convert_string(
249 $GLOBALS['charset_of_file'],
253 if ($GLOBALS['save_on_server'] && strlen($line) > 0) {
254 $write_result = @fwrite
($GLOBALS['file_handle'], $line);
255 if (! $write_result ||
($write_result != strlen($line))) {
256 $GLOBALS['message'] = PMA_Message
::error(
257 __('Insufficient space to save the file %s.')
259 $GLOBALS['message']->addParam($save_filename);
263 if ($time_start >= $time_now +
30) {
264 $time_start = $time_now;
265 header('X-pmaPing: Pong');
268 // We export as file - output normally
272 // We export as html - replace special chars
273 echo htmlspecialchars($line);
277 } // end of the 'PMA_exportOutputHandler()' function
279 // Defines the default <CR><LF> format.
280 // For SQL always use \n as MySQL wants this on all platforms.
281 if ($what == 'sql') {
284 $crlf = PMA_Util
::whichCrlf();
287 $output_kanji_conversion = function_exists('PMA_kanji_str_conv') && $type != 'xls';
289 // Do we need to convert charset?
290 $output_charset_conversion = $asfile
291 && $GLOBALS['PMA_recoding_engine'] != PMA_CHARSET_NONE
292 && isset($charset_of_file) && $charset_of_file != 'utf-8'
295 // Use on the fly compression?
296 $onfly_compression = $GLOBALS['cfg']['CompressOnFly']
297 && ($compression == 'gzip' ||
$compression == 'bzip2');
298 if ($onfly_compression) {
299 $memory_limit = trim(@ini_get
('memory_limit'));
301 if (empty($memory_limit)) {
302 $memory_limit = 2 * 1024 * 1024;
305 if (strtolower(substr($memory_limit, -1)) == 'm') {
306 $memory_limit = (int)substr($memory_limit, 0, -1) * 1024 * 1024;
307 } elseif (strtolower(substr($memory_limit, -1)) == 'k') {
308 $memory_limit = (int)substr($memory_limit, 0, -1) * 1024;
309 } elseif (strtolower(substr($memory_limit, -1)) == 'g') {
310 $memory_limit = (int)substr($memory_limit, 0, -1) * 1024 * 1024 * 1024;
312 $memory_limit = (int)$memory_limit;
315 // Some of memory is needed for other thins and as treshold.
316 // Nijel: During export I had allocated (see memory_get_usage function)
317 // approx 1.2MB so this comes from that.
318 if ($memory_limit > 1500000) {
319 $memory_limit -= 1500000;
322 // Some memory is needed for compression, assume 1/3
326 // Generate filename and mime type if needed
328 $pma_uri_parts = parse_url($cfg['PmaAbsoluteUri']);
329 if ($export_type == 'server') {
330 if (isset($remember_template)) {
331 $GLOBALS['PMA_Config']->setUserValue(
332 'pma_server_filename_template',
333 'Export/file_template_server',
337 } elseif ($export_type == 'database') {
338 if (isset($remember_template)) {
339 $GLOBALS['PMA_Config']->setUserValue(
340 'pma_db_filename_template',
341 'Export/file_template_database',
346 if (isset($remember_template)) {
347 $GLOBALS['PMA_Config']->setUserValue(
348 'pma_table_filename_template',
349 'Export/file_template_table',
354 $filename = PMA_Util
::expandUserString($filename_template);
355 $filename = PMA_sanitizeFilename($filename);
357 // Grab basic dump extension and mime type
358 // Check if the user already added extension;
359 // get the substring where the extension would be if it was included
360 $extension_start_pos = strlen($filename) - strlen(
361 $export_plugin->getProperties()->getExtension()
363 $user_extension = substr($filename, $extension_start_pos, strlen($filename));
364 $required_extension = "." . $export_plugin->getProperties()->getExtension();
365 if (strtolower($user_extension) != $required_extension) {
366 $filename .= $required_extension;
368 $mime_type = $export_plugin->getProperties()->getMimeType();
370 // If dump is going to be compressed, set correct mime_type and add
371 // compression to extension
372 if ($compression == 'bzip2') {
374 $mime_type = 'application/x-bzip2';
375 } elseif ($compression == 'gzip') {
377 $mime_type = 'application/x-gzip';
378 } elseif ($compression == 'zip') {
380 $mime_type = 'application/zip';
384 // Open file on server if needed
385 if ($save_on_server) {
386 $save_filename = PMA_Util
::userDir($cfg['SaveDir'])
387 . preg_replace('@[/\\\\]@', '_', $filename);
389 if (file_exists($save_filename)
390 && ((! $quick_export && empty($onserverover))
392 && $_REQUEST['quick_export_onserverover'] != 'saveitover'))
394 $message = PMA_Message
::error(
395 __('File %s already exists on server, change filename or check overwrite option.')
397 $message->addParam($save_filename);
399 if (is_file($save_filename) && ! is_writable($save_filename)) {
400 $message = PMA_Message
::error(
401 __('The web server does not have permission to save the file %s.')
403 $message->addParam($save_filename);
405 if (! $file_handle = @fopen
($save_filename, 'w')) {
406 $message = PMA_Message
::error(
407 __('The web server does not have permission to save the file %s.')
409 $message->addParam($save_filename);
413 if (isset($message)) {
414 if ($export_type == 'server') {
415 $active_page = 'server_export.php';
416 include 'server_export.php';
417 } elseif ($export_type == 'database') {
418 $active_page = 'db_export.php';
419 include 'db_export.php';
421 $active_page = 'tbl_export.php';
422 include 'tbl_export.php';
429 * Send headers depending on whether the user chose to download a dump file
432 if (! $save_on_server) {
435 // (avoid rewriting data containing HTML with anchors and forms;
436 // this was reported to happen under Plesk)
437 @ini_set
('url_rewriter.tags', '');
438 $filename = PMA_sanitizeFilename($filename);
440 PMA_downloadHeader($filename, $mime_type);
443 if ($export_type == 'database') {
444 $num_tables = count($tables);
445 if ($num_tables == 0) {
446 $message = PMA_Message
::error(__('No tables found in database.'));
447 $active_page = 'db_export.php';
448 include 'db_export.php';
452 $backup_cfgServer = $cfg['Server'];
453 $cfg['Server'] = $backup_cfgServer;
454 unset($backup_cfgServer);
455 echo "\n" . '<div style="text-align: ' . $cell_align_left . '">' . "\n";
456 //echo ' <pre>' . "\n";
459 * Displays a back button with all the $_REQUEST data in the URL
460 * (store in a variable to also display after the textarea)
462 $back_button = '<p>[ <a href="';
463 if ($export_type == 'server') {
464 $back_button .= 'server_export.php?' . PMA_generate_common_url();
465 } elseif ($export_type == 'database') {
466 $back_button .= 'db_export.php?' . PMA_generate_common_url($db);
468 $back_button .= 'tbl_export.php?' . PMA_generate_common_url($db, $table);
471 // Convert the multiple select elements from an array to a string
472 if ($export_type == 'server' && isset($_REQUEST['db_select'])) {
473 $_REQUEST['db_select'] = implode(",", $_REQUEST['db_select']);
474 } elseif ($export_type == 'database' && isset($_REQUEST['table_select'])) {
475 $_REQUEST['table_select'] = implode(",", $_REQUEST['table_select']);
478 foreach ($_REQUEST as $name => $value) {
479 $back_button .= '&' . urlencode($name) . '=' . urlencode($value);
481 $back_button .= '&repopulate=1">Back</a> ]</p>';
484 echo ' <form name="nofunction">' . "\n"
485 // remove auto-select for now: there is no way to select
486 // only a part of the text; anyway, it should obey
487 // $cfg['TextareaAutoSelect']
488 //. ' <textarea name="sqldump" cols="50" rows="30" onclick="this.select();" id="textSQLDUMP" wrap="OFF">' . "\n";
489 . ' <textarea name="sqldump" cols="50" rows="30" id="textSQLDUMP" wrap="OFF">' . "\n";
493 // Fake loop just to allow skip of remain of this code by break, I'd really
494 // need exceptions here :-)
497 // Add possibly some comments to export
498 if (! $export_plugin->exportHeader($db)) {
502 // Will we need relation & co. setup?
503 $do_relation = isset($GLOBALS[$what . '_relation']);
504 $do_comments = isset($GLOBALS[$what . '_include_comments']);
505 $do_mime = isset($GLOBALS[$what . '_mime']);
506 if ($do_relation ||
$do_comments ||
$do_mime) {
507 $cfgRelation = PMA_getRelationsParam();
510 include_once 'libraries/transformations.lib.php';
513 // Include dates in export?
514 $do_dates = isset($GLOBALS[$what . '_dates']);
519 // Gets the number of tables if a dump of a database has been required
520 if ($export_type == 'server') {
521 if (isset($db_select)) {
522 $tmp_select = implode($db_select, '|');
523 $tmp_select = '|' . $tmp_select . '|';
525 // Walk over databases
526 foreach ($GLOBALS['pma']->databases
as $current_db) {
527 if ((isset($tmp_select)
528 && strpos(' ' . $tmp_select, '|' . $current_db . '|'))
529 ||
! isset($tmp_select)
531 if (! $export_plugin->exportDBHeader($current_db)) {
534 if (! $export_plugin->exportDBCreate($current_db)) {
537 if (method_exists($export_plugin, 'exportRoutines')
538 && strpos($GLOBALS['sql_structure_or_data'], 'structure') !== false
539 && isset($GLOBALS['sql_procedure_function'])
541 $export_plugin->exportRoutines($current_db);
544 $tables = PMA_DBI_get_tables($current_db);
546 foreach ($tables as $table) {
547 // if this is a view, collect it for later;
548 // views must be exported after the tables
549 $is_view = PMA_Table
::isView($current_db, $table);
553 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
554 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
556 // for a view, export a stand-in definition of the table
557 // to resolve view dependencies
558 if (! $export_plugin->exportStructure(
559 $current_db, $table, $crlf, $err_url,
560 $is_view ?
'stand_in' : 'create_table', $export_type,
561 $do_relation, $do_comments, $do_mime, $do_dates
566 // if this is a view or a merge table, don't export data
567 if (($GLOBALS[$what . '_structure_or_data'] == 'data'
568 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data')
569 && ! ($is_view || PMA_Table
::isMerge($current_db, $table))
571 $local_query = 'SELECT * FROM ' . PMA_Util
::backquote($current_db)
572 . '.' . PMA_Util
::backquote($table);
573 if (! $export_plugin->exportData($current_db, $table, $crlf, $err_url, $local_query)) {
577 // now export the triggers (needs to be done after the data
578 // because triggers can modify already imported tables)
579 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
580 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
582 if (! $export_plugin->exportStructure(
583 $current_db, $table, $crlf, $err_url,
584 'triggers', $export_type,
585 $do_relation, $do_comments, $do_mime, $do_dates
591 foreach ($views as $view) {
592 // no data export for a view
593 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
594 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
596 if (! $export_plugin->exportStructure(
597 $current_db, $view, $crlf, $err_url,
598 'create_view', $export_type,
599 $do_relation, $do_comments, $do_mime, $do_dates
605 if (! $export_plugin->exportDBFooter($current_db)) {
610 } elseif ($export_type == 'database') {
611 if (! $export_plugin->exportDBHeader($db)) {
615 if (method_exists($export_plugin, 'exportRoutines')
616 && strpos($GLOBALS['sql_structure_or_data'], 'structure') !== false
617 && isset($GLOBALS['sql_procedure_function'])
619 $export_plugin->exportRoutines($db);
624 // $tables contains the choices from the user (via $table_select)
625 foreach ($tables as $table) {
626 // if this is a view, collect it for later; views must be exported after
628 $is_view = PMA_Table
::isView($db, $table);
632 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
633 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
635 // for a view, export a stand-in definition of the table
636 // to resolve view dependencies
637 if (! $export_plugin->exportStructure(
638 $db, $table, $crlf, $err_url,
639 $is_view ?
'stand_in' : 'create_table', $export_type,
640 $do_relation, $do_comments, $do_mime, $do_dates
645 // if this is a view or a merge table, don't export data
646 if (($GLOBALS[$what . '_structure_or_data'] == 'data'
647 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data')
648 && ! ($is_view || PMA_Table
::isMerge($db, $table))
650 $local_query = 'SELECT * FROM ' . PMA_Util
::backquote($db)
651 . '.' . PMA_Util
::backquote($table);
652 if (! $export_plugin->exportData($db, $table, $crlf, $err_url, $local_query)) {
656 // now export the triggers (needs to be done after the data because
657 // triggers can modify already imported tables)
658 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
659 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
661 if (! $export_plugin->exportStructure(
662 $db, $table, $crlf, $err_url,
663 'triggers', $export_type,
664 $do_relation, $do_comments, $do_mime, $do_dates
670 foreach ($views as $view) {
671 // no data export for a view
672 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
673 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
675 if (! $export_plugin->exportStructure(
676 $db, $view, $crlf, $err_url,
677 'create_view', $export_type,
678 $do_relation, $do_comments, $do_mime, $do_dates
685 if (! $export_plugin->exportDBFooter($db)) {
689 if (! $export_plugin->exportDBHeader($db)) {
692 // We export just one table
693 // $allrows comes from the form when "Dump all rows" has been selected
694 if (isset($allrows) && $allrows == '0' && $limit_to > 0 && $limit_from >= 0) {
695 $add_query = ' LIMIT '
696 . (($limit_from > 0) ?
$limit_from . ', ' : '')
702 $is_view = PMA_Table
::isView($db, $table);
703 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
704 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
706 if (! $export_plugin->exportStructure(
707 $db, $table, $crlf, $err_url,
708 $is_view ?
'create_view' : 'create_table', $export_type,
709 $do_relation, $do_comments, $do_mime, $do_dates
714 // If this is an export of a single view, we have to export data;
715 // for example, a PDF report
716 // if it is a merge table, no data is exported
717 if (($GLOBALS[$what . '_structure_or_data'] == 'data'
718 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data')
719 && ! PMA_Table
::isMerge($db, $table)
721 if (! empty($sql_query)) {
722 // only preg_replace if needed
723 if (! empty($add_query)) {
724 // remove trailing semicolon before adding a LIMIT
725 $sql_query = preg_replace('%;\s*$%', '', $sql_query);
727 $local_query = $sql_query . $add_query;
728 PMA_DBI_select_db($db);
730 $local_query = 'SELECT * FROM ' . PMA_Util
::backquote($db)
731 . '.' . PMA_Util
::backquote($table) . $add_query;
733 if (! $export_plugin->exportData($db, $table, $crlf, $err_url, $local_query)) {
737 // now export the triggers (needs to be done after the data because
738 // triggers can modify already imported tables)
739 if ($GLOBALS[$what . '_structure_or_data'] == 'structure'
740 ||
$GLOBALS[$what . '_structure_or_data'] == 'structure_and_data'
742 if (! $export_plugin->exportStructure(
743 $db, $table, $crlf, $err_url,
744 'triggers', $export_type,
745 $do_relation, $do_comments, $do_mime, $do_dates
750 if (! $export_plugin->exportDBFooter($db)) {
754 if (! $export_plugin->exportFooter()) {
761 if ($save_on_server && isset($message)) {
762 if ($export_type == 'server') {
763 $active_page = 'server_export.php';
764 include 'server_export.php';
765 } elseif ($export_type == 'database') {
766 $active_page = 'db_export.php';
767 include 'db_export.php';
769 $active_page = 'tbl_export.php';
770 include 'tbl_export.php';
776 * Send the dump as a file...
778 if (! empty($asfile)) {
779 // Convert the charset if required.
780 if ($output_charset_conversion) {
781 $dump_buffer = PMA_convert_string(
783 $GLOBALS['charset_of_file'],
788 // Do the compression
789 // 1. as a zipped file
790 if ($compression == 'zip') {
791 if (@function_exists
('gzcompress')) {
792 $zipfile = new ZipFile();
793 $zipfile->addFile($dump_buffer, substr($filename, 0, -4));
794 $dump_buffer = $zipfile->file();
796 } elseif ($compression == 'bzip2') {
797 // 2. as a bzipped file
798 if (@function_exists
('bzcompress')) {
799 $dump_buffer = bzcompress($dump_buffer);
801 } elseif ($compression == 'gzip' && PMA_gzencodeNeeded()) {
802 // 3. as a gzipped file
803 // without the optional parameter level because it bugs
804 $dump_buffer = gzencode($dump_buffer);
807 /* If we saved on server, we have to close file now */
808 if ($save_on_server) {
809 $write_result = @fwrite
($file_handle, $dump_buffer);
810 fclose($file_handle);
811 if (strlen($dump_buffer) > 0
812 && (! $write_result ||
($write_result != strlen($dump_buffer)))
814 $message = new PMA_Message(
815 __('Insufficient space to save the file %s.'),
820 $message = new PMA_Message(
821 __('Dump has been saved to file %s.'),
822 PMA_Message
::SUCCESS
,
827 if ($export_type == 'server') {
828 $active_page = 'server_export.php';
829 include_once 'server_export.php';
830 } elseif ($export_type == 'database') {
831 $active_page = 'db_export.php';
832 include_once 'db_export.php';
834 $active_page = 'tbl_export.php';
835 include_once 'tbl_export.php';
839 PMA_Response
::getInstance()->disable();
844 * Displays the dump...
846 * Close the html tags and add the footers if dump is displayed on screen
848 echo '</textarea>' . "\n"
853 echo '</div>' . "\n";
856 <script type
="text/javascript">
858 var $body = $
("body");
860 .width($body.width() - 50)
861 .height($body.height() - 100);