ave-cms/class/class.dbdump.php
2018-05-16 23:14:07 +03:00

643 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* AVE.cms
*
* Класс, предназначенный для создания и восстановления дампов БД через Панель управления
*
* @package AVE.cms
* @version 3.x
* @filesource
* @copyright © 2007-2014 AVE.cms, http://www.ave-cms.ru
*
*/
class AVE_DB_Service
{
/**
* Метка-разделитель SQL-запросов
*
* @public string
*/
public $_delimiter = '#####systemdump#####';
/**
* Дамп базы данных
*
* @public string
*/
public $_database_dump = '';
/**
* Метод, предназначенный для формирования файла дампа базы данных
*
* @return boolean
*/
function _databaseDumpCreate()
{
global $AVE_DB;
if (! (! empty($_REQUEST['ta']) && is_array($_REQUEST['ta'])))
return false;
$search = array("\x00", "\x0a", "\x0d", "\x1a");
$replace = array('\0', '\n', '\r', '\Z');
$this->_database_dump = '';
// Циклически обрабатываем каждую таблицу
foreach ($_REQUEST['ta'] as $table)
{
if (! DB_EXPORT_PREFIX)
$table_export = preg_replace('/^' . PREFIX . '/', '%%PRFX%%', $table);
// Если таблица имеет корректный префикс
if (preg_match('/^' . preg_quote(PREFIX) . '_/', $table))
{
$row = $AVE_DB->Query("SHOW CREATE TABLE " . $table)->FetchArray();
// Сохраняем CREATE и DROP запросы
$this->_database_dump .= "DROP TABLE IF EXISTS `" . (! DB_EXPORT_PREFIX ? $table_export : $table) . "`;" . $this->_delimiter . "\n";
if (! DB_EXPORT_PREFIX)
$this->_database_dump .= str_replace('CREATE TABLE `' . PREFIX . '_', 'CREATE TABLE `%%PRFX%%_', $row[1]) . ";" . $this->_delimiter . "\n\n";
else
$this->_database_dump .= $row[1] . ";" . $this->_delimiter . "\n\n";
$nums = 0;
// Получаем данные, которые в дальнейшем будут вставлены в INSERT запросы.
$sql = $AVE_DB->Query('SELECT * FROM `' . $table . '`');
while ($row = $sql->FetchArray())
{
if ($nums == 0)
{
$nums = $sql->NumFields();
$temp_array = array();
for ($i = 0; $i < $nums; $i++)
{
$temp_array[] = $sql->FieldName($i);
}
$table_list = '(`' . implode('`, `', $temp_array) . '`)';
}
$temp_array = array();
for ($i=0; $i<$nums; $i++)
{
if (! isset($row[$i]))
{
$temp_array[] = 'NULL';
}
elseif ($row[$i] != '')
{
$temp_array[] = "'" . str_replace($search, $replace, addslashes($row[$i])) . "'";
}
else
{
$temp_array[] = "''";
}
}
// Сохряняем INSERT запросы
$this->_database_dump .= 'INSERT INTO `' . (! DB_EXPORT_PREFIX ? $table_export : $table) . '` ' . $table_list . ' VALUES (' . implode(', ', $temp_array) . ");" . $this->_delimiter . "\n";
}
$this->_database_dump .= "\n";
$sql->Close();
}
}
return ! empty($this->_database_dump);
}
/**
* Метод, предназначенный для формирования файла дампа базы данных
*
* @return boolean
*/
function _databaseTopDumpCreate()
{
global $AVE_DB;
$dbtables = array();
$sql = $AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_%'");
while ($row = $sql->FetchArray())
{
array_push($dbtables, $row[0]);
}
$search = array("\x00", "\x0a", "\x0d", "\x1a");
$replace = array('\0', '\n', '\r', '\Z');
$this->_database_dump = '';
// Циклически обрабатываем каждую таблицу
foreach ($dbtables as $table)
{
if (! DB_EXPORT_PREFIX)
$table_export = preg_replace('/^' . PREFIX . '/', '%%PRFX%%', $table);
// Если таблица имеет корректный префикс
if (preg_match('/^' . preg_quote(PREFIX) . '_/', $table))
{
$row = $AVE_DB->Query("SHOW CREATE TABLE " . $table)->FetchArray();
// Сохраняем CREATE и DROP запросы
$this->_database_dump .= "DROP TABLE IF EXISTS `" . (! DB_EXPORT_PREFIX ? $table_export : $table) . "`;" . $this->_delimiter . "\n";
if (! DB_EXPORT_PREFIX)
$this->_database_dump .= str_replace('CREATE TABLE `' . PREFIX . '_', 'CREATE TABLE `%%PRFX%%_', $row[1]) . ";" . $this->_delimiter . "\n\n";
else
$this->_database_dump .= $row[1] . ";" . $this->_delimiter . "\n\n";
$nums = 0;
// Получаем данные, которые в дальнейшем будут вставлены в INSERT запросы.
$sql = $AVE_DB->Query('SELECT * FROM `' . $table . '`');
while ($row = $sql->FetchArray())
{
if ($nums==0)
{
$nums = $sql->NumFields();
$temp_array = array();
for ($i=0; $i<$nums; $i++)
{
$temp_array[] = $sql->FieldName($i);
}
$table_list = '(`' . implode('`, `', $temp_array) . '`)';
}
$temp_array = array();
for ($i=0; $i<$nums; $i++)
{
if (!isset($row[$i]))
{
$temp_array[] = 'NULL';
}
elseif ($row[$i] != '')
{
$temp_array[] = "'" . str_replace($search, $replace, addslashes($row[$i])) . "'";
}
else
{
$temp_array[] = "''";
}
}
// Сохряняем INSERT запросы
$this->_database_dump .= 'INSERT INTO `' . (! DB_EXPORT_PREFIX ? $table_export : $table) . '` ' . $table_list . ' VALUES (' . implode(', ', $temp_array) . ");" . $this->_delimiter . "\n";
}
$this->_database_dump .= "\n";
$sql->Close();
}
}
return ! empty($this->_database_dump);
}
/**
* Внешние методы класса
*/
/**
* Метод, предназначенный для сохранения файла дампа базы данных на жеский диск
*
*/
function databaseDumpExport($top = 0, $exit = 0)
{
global $AVE_Template;
// Если дамп не удалось создать, тогда завершаем работу
if ($top)
{
if (! $this->_databaseTopDumpCreate())
exit;
}
else
{
if (! $this->_databaseDumpCreate())
exit;
}
// Готовим шаблон имени файла
if (isset($_REQUEST['file_name']) AND $_REQUEST['file_name'] != '')
$file_name = prepare_fname($_REQUEST['file_name']);
else
$file_name = preg_replace_ru(array("/%SERVER%/", "/%DATE%/", "/%TIME%/"), array($_SERVER['SERVER_NAME'], date('d.m.y'), date('H.i.s')), DB_EXPORT_TPL);
$dump = (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ
? gzencode($this->_database_dump)
: $this->_database_dump);
if (isset($_REQUEST['server']) && $_REQUEST['server'] == 1)
{
if (! is_dir(BASE_DIR . '/tmp/backup/'))
{
@mkdir(BASE_DIR . '/tmp/backup/', 0777, true);
write_htaccess_deny(BASE_DIR . '/tmp/backup/');
}
@file_put_contents(BASE_DIR . '/tmp/backup/'. $file_name . '.sql'. (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ ? '.gz' : ''), $dump);
@chmod(BASE_DIR . '/tmp/backup/'. $file_name . '.sql', 0777);
if (! $exit)
header('Location:index.php?do=dbsettings&cp=' . SESSION);
else
return BASE_DIR . '/tmp/backup/'. $file_name . '.sql'. (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ ? '.gz' : '');
}
else
{
// Формируем заголовок
header('Content-Type: text/plain');
header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Content-Disposition: attachment; filename=' . $file_name . '.sql'. (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ ? '.gz' : ''));
header('Content-Length: ' . strlen($dump));
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
// Выводим данные
echo $dump;
$this->_database_dump = '';
}
// Выполняем запись системного сообщения в журнал
reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP'));
exit;
}
/**
* Метод, предназначенный для сохранения файла дампа базы данных на жеский диск
*
*/
function databaseDumpFileSave($file = '')
{
global $AVE_Template;
$file = BASE_DIR . '/tmp/backup/'. $file;
// Если дамп не удалось создать, тогда завершаем работу
if (! is_file($file))
return false;
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
/**
* Метод, предназначенный для восстановления базы данных из дампа
*
* @param string $tempdir путь к папке в которую загружается файл дампа
*/
function databaseDumpImport($tempdir)
{
global $AVE_DB, $AVE_Template;
$insert = false;
// Если файл не пустой
if ($_FILES['file']['size'] != 0)
{
// Получаем имя файла и его расширение (должно быть sql)
$fupload_name = $_FILES['file']['name'];
$gz = substr($fupload_name, -3) == '.gz';
$end = substr($fupload_name, -3);
// Если расширение sql, тогда
if ($gz || $end == 'sql')
{
// Если файл не удалось загрузить, формируем сообщение с ошибкой
if (! @move_uploaded_file($_FILES['file']['tmp_name'], $tempdir . $fupload_name))
die('Ошибка при загрузке файла!');
// Устанавливаем права чтения, записи, выполнения на файл
@chmod($fupload_name, 0777);
// Определяем флаг готовности к записи данных в БД
$insert = true;
}
else
{
// В противном случае, если расширение файла НЕ sql, формируем сообщение с ошибкой
$AVE_Template->assign('msg', '<li class="highlight red"><strong>Ошибка:</strong> ' . $AVE_Template->get_config_vars('MAIN_SQL_FILE_ERROR') . '</li>');
}
}
// Если флаг готовности записи установлен, тогда
if ($insert)
{
// Еще раз провреяем наличие загруженного файла
if ($fupload_name != '' && file_exists($tempdir . $fupload_name))
{
// Читаем данные из файла
$handle = @fopen($tempdir . $fupload_name, 'r');
$db_q = @fread($handle, filesize($tempdir . $fupload_name));
fclose($handle);
if ($gz)
$db_q = gzdecode($db_q);
$m_ok = 0;
$m_fail = 0;
// Формируем массив запросов ориентируясь по разделителю указанному в свойстве _delimiter
$querys = @explode($this->_delimiter, $db_q);
// Циклически обрабатываем массив, выполняя каждый запрос
foreach ($querys as $val)
{
if (chop($val) != '')
{
$q = str_replace("\n",'',$val);
$q = $q . ';';
if ($AVE_DB->Query($q))
{
$m_ok++;
}
else
{
$m_fail++;
}
}
}
// Удаляем файл дампа
@unlink($tempdir . $fupload_name);
// Формируем сопроводительные сообщения
$msg = '<li class="highlight green"><strong>' . $AVE_Template->get_config_vars('MAIN_RESTORE_OK') . '</strong><br /><br />'
. $AVE_Template->get_config_vars('MAIN_TABLE_SUCC')
. '<strong>' . $m_ok . '</strong><br/> '
. $AVE_Template->get_config_vars('MAIN_TABLE_ERROR')
. '<strong><span style="color:red">' . $m_fail . '</span></strong></li>';
$AVE_Template->assign('msg', $msg);
}
else // В противном случае, если файл не найден, формируем сообщение с ошибкой
{
$AVE_Template->assign('msg', '<li class="highlight red">'.$AVE_Template->get_config_vars('DB_REPORT_DUMP_ER').'</li>');
}
}
// Выполняем запись системного сообщения в журнал
reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_RECOVER'));
}
/**
* Метод, предназначенный для удаления файла дампа на сервере
*
* @param string $file путь к файлу дампа
*/
function databaseDumpFileDelete($file = '')
{
global $AVE_DB, $AVE_Template;
$file = BASE_DIR . '/tmp/backup/'. $file;
if (! is_file($file))
return false;
if (@unlink($file))
{
reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_DEL_OK') . ' ('.basename($file).')');
}
else
{
reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_DEL_ER') . ' ('.basename($file).')');
}
header('Location:index.php?do=dbsettings&cp=' . SESSION);
}
/**
* Метод, предназначенный для восстановления базы данных из дампа на сервере
*
* @param string $file путь к файлу дампа
*/
function databaseDumpFileImport($file = '')
{
global $AVE_DB, $AVE_Template;
$insert = false;
$file = BASE_DIR . '/tmp/backup/'. $file;
// Если дамп не удалось создать, тогда завершаем работу
if (! is_file($file)) $insert = false;
// Если файл не пустой
if (filesize($file) != 0)
{
// Получаем имя файла и его расширение (должно быть sql)
$file_name = basename($file);
$gz = substr($file_name, -3)=='.gz';
$end = substr($file_name, -3);
// Если расширение sql, тогда
if ($gz || $end == 'sql')
{
// Определяем флаг готовности к записи данных в БД
$insert = true;
}
else
{
// В противном случае, если расширение файла НЕ sql, формируем сообщение с ошибкой
$AVE_Template->assign('msg', '<li class="highlight red"><strong>Ошибка:</strong> ' . $AVE_Template->get_config_vars('MAIN_SQL_FILE_ERROR') . '</li>');
}
}
// Если флаг готовности записи установлен, тогда
if ($insert)
{
// Еще раз провреяем наличие загруженного файла
if ($file_name != '' && file_exists($file))
{
// Читаем данные из файла
$handle = @fopen($file, 'r');
$db_q = @fread($handle, filesize($file));
fclose($handle);
if($gz)$db_q=gzdecode($db_q);
$m_ok = 0;
$m_fail = 0;
// Формируем массив запросов ориентируясь по разделителю указанному в свойстве _delimiter
$querys = @explode($this->_delimiter, $db_q);
// Циклически обрабатываем массив, выполняя каждый запрос
foreach ($querys as $val)
{
if (chop($val) != '')
{
$q = str_replace("\n",'',$val);
$q = $q . ';';
@$q = str_replace('%%PRFX%%', PREFIX, $q);
if ($AVE_DB->Query($q))
{
$m_ok++;
}
else
{
$m_fail++;
}
}
}
// Формируем сопроводительные сообщения
$msg = '<li class="highlight green"><strong>' . $AVE_Template->get_config_vars('MAIN_RESTORE_OK') . '</strong><br /><br />'
. $AVE_Template->get_config_vars('MAIN_TABLE_SUCC')
. '<strong>' . $m_ok . '</strong><br/> '
. $AVE_Template->get_config_vars('MAIN_TABLE_ERROR')
. '<strong><span style="color:red">' . $m_fail . '</span></strong></li>';
$AVE_Template->assign('msg', $msg);
}
else // В противном случае, если файл не найден, формируем сообщение с ошибкой
{
$AVE_Template->assign('msg', '<li class="highlight red">'.$AVE_Template->get_config_vars('DB_REPORT_DUMP_ER').'</li>');
}
}
// Выполняем запись системного сообщения в журнал
reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_RECOVER') . ' ('.$file_name.')');
}
/**
* Метод, предназначенный для оптимизации таблиц базы данных
*
*/
function databaseTableOptimize()
{
global $AVE_DB, $AVE_Template;
if (! empty($_POST['ta']) && is_array($_POST['ta']))
{
// Выполняем запрос на оптимизацию
$AVE_DB->Query("OPTIMIZE TABLE `" . implode("`, `", $_POST['ta']) . "`");
// Выполняем запись системного сообщения в журнал
reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_OPTIM'));
}
}
/**
* Метод, предназначенный для восстановления повреждённых таблиц базы данных
*
*/
function databaseTableRepair()
{
global $AVE_DB, $AVE_Template;
if (! empty($_POST['ta']) && is_array($_POST['ta']))
{
// Выполняем запрос на восстановление
$AVE_DB->Query("REPAIR TABLE `" . implode("`, `", $_POST['ta']) . "`");
// Выполняем запись системного сообщения в журнал
reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_TABLE'));
}
}
/**
* Метод, предназначенный для формирования списка всех таблиц в БД
*
* @return string
*/
function databaseTableGet()
{
global $AVE_DB;
$tables = '';
// Получаем список всех таблиц, которые имею префикс, указанный в конфигурации системы
$sql = $AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_%'");
while ($row = $sql->FetchArray())
{
$tables .= '<option value="' . $row[0] . '" selected="selected">' . substr($row[0], 1+strlen(PREFIX)) . '</option>';
}
$sql->Close();
// Возвращаем полученный список
return $tables;
}
/**
* Метод, предназначенный для вывода всех sql файлов в папке backup
*
* @return string
*/
function databaseFilesGet()
{
$dir = BASE_DIR . '/tmp/backup/';
if($handle = opendir($dir))
{
$files = array();
while (false !== ($file = readdir($handle)))
{
if ($file != "." && $file != ".." && (substr($file, -3) == 'sql' || substr($file, -2) == 'gz'))
{
if(is_file($dir . '/' . $file))
{
$files[] = array(
'name' => $file,
'data' => (filectime($dir . '/' . $file)),
'size' => (filesize($dir . '/' . $file))
);
}
}
}
closedir($handle);
}
return msort($files, 'data', null, SORT_DESC);
}
}
?>