- We do On-the-fly file writting for everything in backups, should speed things up

- Removed the ability to make archives for backups... Its one sql file, no need to use some heavy archive to store it...
- Made it easier to use the restore feature
- Flushed the data buffer at the end of every insert statement, this should make large tables (like posts and topics) faster to backup
- Some bug fixes :D


git-svn-id: file:///svn/phpbb/trunk@5708 89ea8834-ac86-4346-8a33-228a782c2dd0
This commit is contained in:
David M 2006-03-25 01:03:17 +00:00
parent e8e4d92d01
commit 529aabd46d
3 changed files with 218 additions and 115 deletions

View file

@ -11,7 +11,7 @@
<legend>{L_RESTORE_OPTIONS}</legend> <legend>{L_RESTORE_OPTIONS}</legend>
<dl> <dl>
<dt><label for="user">{L_SELECT_FILE}:</label></dt> <dt><label for="user">{L_SELECT_FILE}:</label></dt>
<dd><select id="file" name="file" size="10"><!-- BEGIN files --><option value="{files.FILE}"<!-- IF not files.SUPPORTED --> disabled="disabled"<!-- ENDIF --><!-- IF files.SELECTED --> selected="selected"<!-- ENDIF -->>{files.FILE}</option><!-- END files --></select></dd> <dd><select id="file" name="file" size="10"><!-- BEGIN files --><option value="{files.FILE}"<!-- IF files.S_LAST_ROW --> selected="selected"<!-- ENDIF -->>{files.NAME}</option><!-- END files --></select></dd>
</dl> </dl>
</fieldset> </fieldset>
<fieldset class="submit-buttons"> <fieldset class="submit-buttons">
@ -49,13 +49,13 @@
</dl> </dl>
<dl> <dl>
<dt><label for="user">{L_FILE_TYPE}:</label></dt> <dt><label for="user">{L_FILE_TYPE}:</label></dt>
<!-- BEGIN methods --> <dd><!-- BEGIN methods -->
<dd><input name="method" id="method" type="radio" value="{methods.TYPE}"<!-- IF methods.S_FIRST_ROW -->checked="checked"<!-- ENDIF --> />&nbsp;{methods.TYPE}</dd> <input name="method" id="method" type="radio" value="{methods.TYPE}"<!-- IF methods.S_FIRST_ROW -->checked="checked"<!-- ENDIF --> />&nbsp;{methods.TYPE}
<!-- END methods --> <!-- END methods --></dd>
</dl> </dl>
<dl> <dl>
<dt><label for="user">{L_ACTION}:</label></dt> <dt><label for="user">{L_ACTION}:</label></dt>
<dd><input type="radio" name="where" value="download" id="where" checked="checked" />&nbsp;{L_DOWNLOAD}&nbsp;&nbsp;<input type="radio" name="where" value="store" id="where" />&nbsp;{L_STORE_LOCAL}</dd> <dd><input type="radio" name="where" value="store_and_download" id="where" checked="checked" />&nbsp;{L_STORE_AND_DOWNLOAD}&nbsp;&nbsp;<input type="radio" name="where" value="store" id="where" />&nbsp;{L_STORE_LOCAL}&nbsp;&nbsp;<input type="radio" name="where" value="download" id="where" />&nbsp;{L_DOWNLOAD}</dd>
</dl> </dl>
<dl> <dl>
<dt><label for="user">{L_TABLE_SELECT}:</label></dt> <dt><label for="user">{L_TABLE_SELECT}:</label></dt>

View file

@ -20,8 +20,6 @@ class acp_database
global $db, $user, $auth, $template, $table_prefix; global $db, $user, $auth, $template, $table_prefix;
global $config, $SID, $phpbb_root_path, $phpbb_admin_path, $phpEx; global $config, $SID, $phpbb_root_path, $phpbb_admin_path, $phpEx;
include($phpbb_root_path . 'includes/functions_compress.'.$phpEx);
$user->add_lang('acp/database'); $user->add_lang('acp/database');
$this->tpl_name = 'acp_database'; $this->tpl_name = 'acp_database';
@ -49,17 +47,58 @@ class acp_database
@set_time_limit(1200); @set_time_limit(1200);
$filename = time(); $filename = time();
$time_start = microtime(true); //$time_start = microtime(true);
// We set up the info needed for our on-the-fly creation :D
switch ($format)
{
case 'text':
$ext = '.sql';
$open = 'fopen';
$write = 'fwrite';
$close = 'fclose';
$oper = '';
$mimetype = 'text/x-sql';
break;
case 'bzip2':
$ext = '.sql.bz2';
$open = 'bzopen';
$write = 'bzwrite';
$close = 'bzclose';
$oper = 'bzcompress';
$mimetype = 'application/x-bzip2';
break;
case 'gzip':
$ext = '.sql.gz';
$open = 'gzopen';
$write = 'gzwrite';
$close = 'gzclose';
$oper = 'gzencode';
$mimetype = 'application/x-gzip';
break;
}
// We write the file to "store" first (and then compress the file) to not use too much // We write the file to "store" first (and then compress the file) to not use too much
// memory. The server process can be easily killed by storing too much data at once. // memory. The server process can be easily killed by storing too much data at once.
$file = $phpbb_root_path . 'store/' . $filename . '.sql';
$fp = fopen($file, 'a');
if (!$fp) if ($where == 'store')
{ {
trigger_error('Unable to write temporary file to storage folder'); $file = $phpbb_root_path . 'store/' . $filename . $ext;
$fp = $open($file, 'w');
if (!$fp)
{
trigger_error('Unable to write temporary file to storage folder');
}
}
else
{
$name = $filename . $ext;
header('Pragma: no-cache');
header("Content-Type: $mimetype; name=\"$name\"");
header("Content-disposition: attachment; filename=$name");
} }
// All of the generated queries go here // All of the generated queries go here
@ -67,8 +106,8 @@ class acp_database
$sql_data .= "#\n"; $sql_data .= "#\n";
$sql_data .= "# phpBB Backup Script\n"; $sql_data .= "# phpBB Backup Script\n";
$sql_data .= "# Dump of tables for $table_prefix\n"; $sql_data .= "# Dump of tables for $table_prefix\n";
$sql_data .= "#\n# DATE : " . gmdate("d-m-Y H:i:s", $filename) . " GMT\n"; $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $filename) . " GMT\n";
$sql_data .= "# START : $time_start\n"; //$sql_data .= "# START : $time_start\n";
$sql_data .= "#\n"; $sql_data .= "#\n";
switch (SQL_LAYER) switch (SQL_LAYER)
@ -97,14 +136,29 @@ class acp_database
case 'postgres': case 'postgres':
$sql_data .= '# Table: ' . $table_name . "\n"; $sql_data .= '# Table: ' . $table_name . "\n";
$sql_data .= "DROP TABLE $table_name;\n"; $sql_data .= "DROP TABLE $table_name;\n";
default:
trigger_error('KungFuDeathGrip');
break; break;
} }
$sql_data .= $this->get_table_structure($table_name);
} }
$sql_data .= $this->get_table_structure($table_name);
// Now write the data for the first time. :) // Now write the data for the first time. :)
fwrite($fp, $sql_data); if ($where !== 'download')
{
$write($fp, $sql_data);
}
else
{
if (!empty($oper))
{
echo $oper($sql_data);
}
else
{
echo $sql_data;
}
}
$sql_data = ''; $sql_data = '';
@ -155,9 +209,23 @@ class acp_database
} }
$sql_data .= $schema_insert . implode(', ', $values) . ");\n"; $sql_data .= $schema_insert . implode(', ', $values) . ");\n";
$values = array(); if ($where !== 'download')
fwrite($fp, $sql_data); {
$write($fp, $sql_data);
}
else
{
if (!empty($oper))
{
echo $oper($sql_data);
}
else
{
echo $sql_data;
}
}
$sql_data = ''; $sql_data = '';
} }
mysqli_free_result($result); mysqli_free_result($result);
} }
@ -209,9 +277,24 @@ class acp_database
} }
$sql_data .= $schema_insert . implode(', ', $values) . ");\n"; $sql_data .= $schema_insert . implode(', ', $values) . ");\n";
$values = array(); if ($where !== 'download')
fwrite($fp, $sql_data); {
$write($fp, $sql_data);
}
else
{
if (!empty($oper))
{
echo $oper($sql_data);
}
else
{
echo $sql_data;
}
}
$sql_data = ''; $sql_data = '';
$values = array();
} }
mysql_free_result($result); mysql_free_result($result);
} }
@ -219,7 +302,7 @@ class acp_database
case 'sqlite': case 'sqlite':
$col_types = sqlite_fetch_column_types($name, $db->db_connect_id); $col_types = sqlite_fetch_column_types($table_name, $db->db_connect_id);
$sql = "SELECT * FROM $table_name"; $sql = "SELECT * FROM $table_name";
$result = $db->sql_query($sql); $result = $db->sql_query($sql);
@ -246,10 +329,25 @@ class acp_database
$data[] = $row_data; $data[] = $row_data;
} }
$sql_data .= 'INSERT INTO ' . $name . ' (' . implode(', ', $names) . ') VALUES ('. implode(', ', $data) .");\n"; $sql_data .= 'INSERT INTO ' . $table_name . ' (' . implode(', ', $names) . ') VALUES ('. implode(', ', $data) .");\n";
fwrite($fp, $sql_data); if ($where !== 'download')
{
$write($fp, $sql_data);
}
else
{
if (!empty($oper))
{
echo $oper($sql_data);
}
else
{
echo $sql_data;
}
}
$sql_data = ''; $sql_data = '';
} }
$db->sql_freeresult($result); $db->sql_freeresult($result);
break; break;
@ -313,10 +411,25 @@ class acp_database
// Take the ordered fields and their associated data and build it // Take the ordered fields and their associated data and build it
// into a valid sql statement to recreate that field in the data. // into a valid sql statement to recreate that field in the data.
$sql_data .= "INSERT INTO $name (" . implode(', ', $schema_fields) . ') VALUES(' . implode(', ', $schema_vals) . ");\n"; $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES(' . implode(', ', $schema_vals) . ");\n";
fwrite($fp, $sql_data); if ($where !== 'download')
{
$write($fp, $sql_data);
}
else
{
if (!empty($oper))
{
echo $oper($sql_data);
}
else
{
echo $sql_data;
}
}
$sql_data = ''; $sql_data = '';
} }
$db->sql_freeresult($result); $db->sql_freeresult($result);
break; break;
@ -334,61 +447,41 @@ class acp_database
break; break;
} }
$time_stop = microtime(true); /*$time_stop = microtime(true);
$sql_data .= "# END : $time_stop\n"; $sql_data .= "# END : $time_stop\n";
$sql_data .= "# DIFF : ".($time_stop-$time_start); $sql_data .= "# DIFF : ".($time_stop-$time_start);*/
fwrite($fp, $sql_data); if ($where !== 'download')
fclose($fp); {
$write($fp, $sql_data);
$close($fp);
}
else
{
if (!empty($oper))
{
echo $oper($sql_data);
}
else
{
echo $sql_data;
}
exit;
}
unset($sql_data); unset($sql_data);
// Base file name if ($where == 'store_and_download')
$file = $phpbb_root_path . 'store/' . $filename . $format;
switch ($format)
{ {
case '.zip': $name = $filename . $ext;
case '.tar.bz2':
case '.tar.gz':
case '.tar':
if ($format == '.zip') $fp = fopen("{$phpbb_root_path}store/$name", 'rb');
{ while ($buffer = fread($fp, 1024))
$compress = new compress_zip('w', $file); {
} echo $buffer;
else }
{ fclose($fp);
$compress = new compress_tar('w', $file, $format); exit;
}
$compress->add_data(file_get_contents($phpbb_root_path . 'store/' . $filename . '.sql'), "$filename.sql");
$compress->close();
if ($where == 'download')
{
$compress->download($filename);
exit;
}
break;
case '.sql':
if ($where == 'download')
{
$mimetype = 'text/sql';
header('Pragma: no-cache');
header("Content-Type: $mimetype; name=\"$filename.sql\"");
header("Content-disposition: attachment; filename=$filename.sql");
$fp = fopen("{$phpbb_root_path}store/$filename.sql", 'rb');
while ($buffer = fread($fp, 1024))
{
echo $buffer;
}
fclose($fp);
exit;
}
} }
add_log('admin', 'LOG_DB_BACKUP'); add_log('admin', 'LOG_DB_BACKUP');
trigger_error($user->lang['BACKUP_SUCCESS']); trigger_error($user->lang['BACKUP_SUCCESS']);
@ -451,8 +544,18 @@ class acp_database
'U_ACTION' => $this->u_action . '&amp;action=download' 'U_ACTION' => $this->u_action . '&amp;action=download'
)); ));
$methods = array('.sql'); $methods = array('text');
$methods = array_merge($methods, compress::methods()); $available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2');
foreach ($available_methods as $type => $module)
{
if (!@extension_loaded($module))
{
continue;
}
$methods[] = $type;
}
foreach ($methods as $type) foreach ($methods as $type)
{ {
$template->assign_block_vars('methods', array( $template->assign_block_vars('methods', array(
@ -468,30 +571,24 @@ class acp_database
{ {
case 'submit': case 'submit':
$file = request_var('file', ''); $file = request_var('file', '');
preg_match('#^(\d{10})\.(sql|zip|tar(?:\.(?:gz|bz2))?)$#', $file, $matches); $data = '';
$format = '.' . $matches[2];
switch ($format)
{
case '.zip':
case '.tar.bz2':
case '.tar.gz':
case '.tar':
if ($format == '.zip')
{
$compress = new compress_zip('r', $phpbb_root_path . 'store/' . $file);
}
else
{
$compress = new compress_tar('r', $phpbb_root_path . 'store/' . $file, $format);
}
$compress->extract($phpbb_root_path . 'store/'); preg_match('#^(\d{10})\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches);
$compress->close();
switch ($matches[2])
{
case 'sql':
$data = file_get_contents($phpbb_root_path . 'store/' . $matches[0]);
break;
case 'sql.bz2':
$data = bzdecompress(file_get_contents($phpbb_root_path . 'store/' . $matches[0]));
break;
case 'sql.gz':
$data = implode(gzfile($phpbb_root_path . 'store/' . $matches[0]));
break; break;
} }
$data = file_get_contents($phpbb_root_path . 'store/' . $matches[1] . '.sql'); if (!empty($data))
if ($data != '')
{ {
// Strip out sql comments... // Strip out sql comments...
remove_remarks($data); remove_remarks($data);
@ -514,30 +611,34 @@ class acp_database
default: default:
$selected = $stop = false; $selected = $stop = false;
$methods = compress::methods(); $methods = array('sql');
$methods[] = '.sql'; $available_methods = array('sql.gz' => 'zlib', 'sql.bz2' => 'bz2');
foreach ($available_methods as $type => $module)
{
if (!@extension_loaded($module))
{
continue;
}
$methods[] = $type;
}
$dir = $phpbb_root_path . 'store/'; $dir = $phpbb_root_path . 'store/';
$dh = opendir($dir); $dh = opendir($dir);
while (($file = readdir($dh)) !== false) while (($file = readdir($dh)) !== false)
{ {
if (preg_match('#^\d{10}\.(sql|zip|tar(?:\.(?:gz|bz2))?)$#', $file, $matches)) if (preg_match('#^(\d{10})\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches))
{ {
$supported = in_array('.' . $matches[1], $methods); $supported = in_array($matches[2], $methods);
if ($supported && !$selected && !$stop)
if ($supported == 'true')
{ {
$selected = true; $template->assign_block_vars('files', array(
$stop = true; 'FILE' => $file,
'NAME' => gmdate("d-m-Y H:i:s", $matches[1]),
'SUPPORTED' => $supported
));
} }
else
{
$selected = false;
}
$template->assign_block_vars('files', array(
'FILE' => $file,
'SUPPORTED' => $supported,
'SELECTED' => $selected
));
} }
} }
closedir($dh); closedir($dh);
@ -610,7 +711,6 @@ class acp_database
} }
$db->sql_freeresult($result); $db->sql_freeresult($result);
$field = array();
foreach ($index as $key => $columns) foreach ($index as $key => $columns)
{ {
$line = ' '; $line = ' ';

View file

@ -41,8 +41,11 @@ $lang = array_merge($lang, array(
'TABLE_SELECT' => 'Table Select', 'TABLE_SELECT' => 'Table Select',
'FILE_TYPE' => 'File Type', 'FILE_TYPE' => 'File Type',
'STORE_LOCAL' => 'Store file locally', 'STORE_LOCAL' => 'Store file locally',
'SELECT_ALL' => 'Select all',
'DESELECT_ALL' => 'Deselect all',
'BACKUP_SUCCESS' => 'The backup file has been created successfully in the location you specified', 'BACKUP_SUCCESS' => 'The backup file has been created successfully in the location you specified',
'STORE_AND_DOWNLOAD' => 'Store and Download',
'ACP_RESTORE' => 'Restore', 'ACP_RESTORE' => 'Restore',
'ACP_RESTORE_EXPLAIN' => 'This will perform a full restore of all phpBB tables from a saved file. You can <u>either</u> upload the backup file via this form or upload it manually to a location on the server. If your server supports it you may use a gzip compressed text file and it will automatically be decompressed. <b>WARNING</b> This will overwrite any existing data. The restore may take a long time to process please do not move from this page till it is complete.', 'ACP_RESTORE_EXPLAIN' => 'This will perform a full restore of all phpBB tables from a saved file. You can <u>either</u> upload the backup file via this form or upload it manually to a location on the server. If your server supports it you may use a gzip compressed text file and it will automatically be decompressed. <b>WARNING</b> This will overwrite any existing data. The restore may take a long time to process please do not move from this page till it is complete.',
'SELECT_FILE' => 'Select a file', 'SELECT_FILE' => 'Select a file',