mirror of
https://github.com/avecms/AVE.cms.git
synced 2025-01-22 15:30:07 +00:00
643 lines
19 KiB
PHP
Executable File
643 lines
19 KiB
PHP
Executable File
<?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);
|
||
}
|
||
}
|
||
?>
|