重构数据备份和还原功能模块
This commit is contained in:
parent
ca9e679729
commit
fb24158e80
@ -11,171 +11,211 @@ namespace app\admin\controller;
|
||||
|
||||
use app\admin\BaseController;
|
||||
use backup\Backup;
|
||||
use think\facade\Session;
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
|
||||
class Database extends BaseController
|
||||
{
|
||||
protected $db = '', $datadir;
|
||||
public function initialize()
|
||||
//数据表列表
|
||||
public function database()
|
||||
{
|
||||
parent::initialize();
|
||||
$this->config = array(
|
||||
'path' => './backup/', // 数据库备份路径
|
||||
'part' => 20971520, // 数据库备份卷大小
|
||||
'compress' => 0, // 数据库备份文件是否启用压缩 0不压缩 1 压缩
|
||||
'level' => 9, // 数据库备份文件压缩级别 1普通 4 一般 9最高
|
||||
);
|
||||
$this->db = new Backup($this->config);
|
||||
}
|
||||
|
||||
// 数据列表
|
||||
public function database()
|
||||
{
|
||||
if (request()->isAjax()) {
|
||||
// 数据信息
|
||||
$list = $this->db->dataList();
|
||||
// 计算总大小
|
||||
$total = 0;
|
||||
foreach ($list as $k => $v) {
|
||||
$total += $v['data_length'];
|
||||
$list[$k]['data_size'] = $v['data_length'];
|
||||
$list[$k]['data_length'] = format_bytes($v['data_length']);
|
||||
if (request()->isAjax()) {
|
||||
// 数据信息
|
||||
$db = new Backup();
|
||||
$list = $db->dataList();
|
||||
// 计算总大小
|
||||
$total = 0;
|
||||
foreach ($list as $k => $v) {
|
||||
$total += $v['data_length'];
|
||||
$list[$k]['data_size'] = $v['data_length'];
|
||||
$list[$k]['data_length'] = format_bytes($v['data_length']);
|
||||
}
|
||||
// 提示信息
|
||||
$dataTips = '数据库中共有<strong> ' . count($list) . '</strong> 张表,共计 <strong>' . format_bytes($total) . '</strong>大小。';
|
||||
$data['data'] = $list;
|
||||
return table_assign(0, $dataTips, $data);
|
||||
}
|
||||
return view();
|
||||
}
|
||||
|
||||
//备份数据
|
||||
public function backup()
|
||||
{
|
||||
$db= new Backup();
|
||||
if(request()->isPost()){
|
||||
$tables=get_params('tables');
|
||||
$fileinfo =$db->getFile();
|
||||
//检查是否有正在执行的任务
|
||||
$lock = "{$fileinfo['filepath']}backup.lock";
|
||||
if(is_file($lock)){
|
||||
return to_assign(2, '检测到有一个备份任务未完成');
|
||||
} else {
|
||||
//创建锁文件
|
||||
file_put_contents($lock,time());
|
||||
}
|
||||
// 提示信息
|
||||
$dataTips = '数据库中共有<strong> ' . count($list) . '</strong> 张表,共计 <strong>' . format_bytes($total) . '</strong>大小。';
|
||||
$data['data'] = $list;
|
||||
return table_assign(0, $dataTips, $data);
|
||||
}
|
||||
return view();
|
||||
}
|
||||
|
||||
// 备份
|
||||
public function backup()
|
||||
{
|
||||
$tables = get_params('id');
|
||||
if (!empty($tables)) {
|
||||
$tables = explode(',', $tables);
|
||||
foreach ($tables as $table) {
|
||||
$this->db->setFile()->backup($table, 0);
|
||||
// 检查备份目录是否可写
|
||||
if(!is_writeable($fileinfo['filepath'])){
|
||||
return to_assign(1, '备份目录不存在或不可写,请检查后重试!');
|
||||
}
|
||||
add_log('bak');
|
||||
return to_assign(0, '备份成功!');
|
||||
} else {
|
||||
return to_assign(1, '请选择要备份的表');
|
||||
}
|
||||
}
|
||||
|
||||
//缓存锁文件
|
||||
Session::set('lock', $lock);
|
||||
//缓存备份文件信息
|
||||
Session::set('backup_file', $fileinfo['file']);
|
||||
//缓存要备份的表
|
||||
Session::set('backup_tables', $tables);
|
||||
//创建备份文件
|
||||
if(false !== $db->Backup_Init()){
|
||||
return to_assign(0, '初始化成功',['tab'=>['id' => 0, 'start' => 0,'table'=>$tables[0]]]);
|
||||
}else{
|
||||
return to_assign(1, '初始化失败,备份文件创建失败!');
|
||||
}
|
||||
}else if(request()->isGet()){
|
||||
$tables = Session::get('backup_tables');
|
||||
$file=Session::get('backup_file');
|
||||
$id=get_params('id');
|
||||
$start=get_params('start');
|
||||
$start= $db->setFile($file)->backup($tables[$id], $start);
|
||||
if(false === $start){
|
||||
return to_assign(1, '备份出错!');
|
||||
}else if(0 === $start){
|
||||
if(isset($tables[++$id])){
|
||||
return to_assign(0, '备份完成',['tab'=>['id' => $id, 'start' => 0,'table'=>$tables[$id-1]]]);
|
||||
} else { //备份完成,清空缓存
|
||||
unlink(Session::get('lock'));
|
||||
Session::delete('backup_tables');
|
||||
Session::delete('backup_file');
|
||||
add_log('bak');
|
||||
return to_assign(0, '备份完成',['tab'=>['start' => 'ok','table'=>$tables[$id-1]]]);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return to_assign(1, '参数错误!');
|
||||
}
|
||||
}
|
||||
|
||||
// 优化
|
||||
public function optimize()
|
||||
{
|
||||
$tables = get_params('id');
|
||||
if (empty($tables)) {
|
||||
return to_assign(0, '请选择要优化的表');
|
||||
//优化表
|
||||
public function optimize($tables= null)
|
||||
{
|
||||
$db= new Backup();
|
||||
//return to_assign(0, $db->optimize($tables));
|
||||
if($db->optimize($tables)){
|
||||
add_log('optimize');
|
||||
return to_assign(0, '数据表优化完成');
|
||||
}else{
|
||||
return to_assign(1, '数据表优化出错请重试');
|
||||
}
|
||||
$tables = explode(',', $tables);
|
||||
if ($this->db->optimize($tables)) {
|
||||
add_log('optimize');
|
||||
return to_assign(0, '数据表优化成功!');
|
||||
} else {
|
||||
return to_assign(1, '数据表优化出错请重试');
|
||||
}
|
||||
}
|
||||
|
||||
// 修复
|
||||
public function repair()
|
||||
{
|
||||
$tables = get_params('id');
|
||||
if (empty($tables)) {
|
||||
return to_assign(1, '请选择要修复的表');
|
||||
}
|
||||
$tables = explode(',', $tables);
|
||||
if ($this->db->repair($tables)) {
|
||||
add_log('repair');
|
||||
return to_assign(0, '数据表修复成功');
|
||||
} else {
|
||||
return to_assign(1, '数据表修复出错请重试');
|
||||
}
|
||||
}
|
||||
|
||||
// 还原列表
|
||||
public function backuplist()
|
||||
{
|
||||
// 数据信息
|
||||
$list = $this->db->fileList();
|
||||
$listNew = [];
|
||||
$indx = 0;
|
||||
}
|
||||
|
||||
//修复表
|
||||
public function repair($tables= null)
|
||||
{
|
||||
$db= new Backup();
|
||||
//return to_assign(0, $db->repair($tables));
|
||||
if($db->repair($tables)){
|
||||
add_log('repair');
|
||||
return to_assign(0, '数据表修复完成');
|
||||
}else{
|
||||
return to_assign(1, '数据表修复出错请重试');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//备份文件列表
|
||||
public function backuplist()
|
||||
{
|
||||
$db= new Backup();
|
||||
$list = $db->fileList();
|
||||
$fileinfo =$db->getFile();
|
||||
$lock = "{$fileinfo['filepath']}backup.lock";
|
||||
$lock_time = 0;
|
||||
if(is_file($lock)){
|
||||
$lock_time = file_get_contents($lock);
|
||||
}
|
||||
$listNew = [];
|
||||
$indx = 0;
|
||||
foreach ($list as $k => $v) {
|
||||
$listNew[$indx]['time'] = $k;
|
||||
$listNew[$indx]['data'][] = $v;
|
||||
$listNew[$indx]['timespan'] = $v['time'];
|
||||
$listNew[$indx]['data'] = $v;
|
||||
$indx++;
|
||||
// $listNew[$k]['list'] = $list[$k];
|
||||
}
|
||||
$list = $listNew;
|
||||
array_multisort(array_column($list, 'time'), SORT_DESC, $list);
|
||||
return view('', ['list' => $list]);
|
||||
}
|
||||
|
||||
// 执行还原数据库操作
|
||||
public function import(int $id)
|
||||
{
|
||||
$list = $this->db->getFile('timeverif', $id);
|
||||
$this->db->setFile($list)->import(1);
|
||||
add_log('reduction');
|
||||
return to_assign(0, '还原成功!');
|
||||
}
|
||||
|
||||
// 下载
|
||||
public function downfile(string $name)
|
||||
{
|
||||
$file_name = $name; //得到文件名
|
||||
header("Content-type:text/html;charset=utf-8");
|
||||
$file_name = iconv("utf-8", "gb2312", $file_name); // 转换编码
|
||||
$file_sub_path = $this->config['path']; //确保文件在这个路径下面,换成你文件所在的路径
|
||||
$file_path = $file_sub_path . $file_name;
|
||||
# 将反斜杠 替换成正斜杠
|
||||
$file_path = str_replace('\\', '/', $file_path);
|
||||
if (!file_exists($file_path)) {
|
||||
$this->error($file_path);exit; //如果提示这个错误,很可能你的路径不对,可以打印$file_sub_path查看
|
||||
}
|
||||
$fp = fopen($file_path, "r"); // 以可读的方式打开这个文件
|
||||
# 如果出现图片无法打开,可以在这个位置添加函数
|
||||
ob_clean(); # 清空擦掉,输出缓冲区。
|
||||
$file_size = filesize($file_path);
|
||||
//下载文件需要用到的头
|
||||
Header("Content-type: application/octet-stream");
|
||||
Header("Accept-Ranges: bytes");
|
||||
Header("Accept-Length:" . $file_size);
|
||||
Header("Content-Disposition: attachment; filename = " . $file_name);
|
||||
$buffer = 1024000;
|
||||
$file_count = 0;
|
||||
while (!feof($fp) && $file_count < $file_size) {
|
||||
$file_con = fread($fp, $buffer);
|
||||
$file_count += $buffer;
|
||||
echo $file_con;
|
||||
}
|
||||
fclose($fp); //关闭这个打开的文件
|
||||
}
|
||||
|
||||
// 删除sql文件
|
||||
public function del(string $id)
|
||||
{
|
||||
if (request()->isAjax()) {
|
||||
if (strpos($id, ',') !== false) {
|
||||
$idArr = explode(',', $id);
|
||||
foreach ($idArr as $k => $v) {
|
||||
$this->db->delFile($v);
|
||||
return view('',['list'=>$list,'lock_time' => $lock_time]);
|
||||
}
|
||||
|
||||
//数据还原
|
||||
public function import($time = 0, $part = null, $start = null)
|
||||
{
|
||||
$db= new Backup();
|
||||
$time =(int)$time;
|
||||
if(is_numeric($time) && is_null($part) && is_null($start)){
|
||||
$list = $db->getFile('timeverif',$time);
|
||||
if(is_array($list)){
|
||||
Session::set('backup_list', $list);
|
||||
return to_assign(0, '初始化完成',array('part' => 1, 'start' => 0,'time' => $time));
|
||||
}else{
|
||||
return to_assign(1, '备份文件可能已经损坏,请检查');
|
||||
}
|
||||
}else if(is_numeric($part) && is_numeric($start)){
|
||||
$list=Session::get('backup_list');
|
||||
$part =(int)$part;
|
||||
$start =(int)$start;
|
||||
$start= $db->setFile($list)->import($start,$time,$part);
|
||||
if(false===$start){
|
||||
return to_assign(1, '还原数据出错,请重试');
|
||||
}elseif(0 === $start){
|
||||
if(isset($list[++$part])){
|
||||
$data = array('part' => $part, 'start' => 0,'time' => $time);
|
||||
return to_assign(0, "正在还原...卷{$part},请勿关闭当前页面",$data);
|
||||
} else {
|
||||
Session::delete('backup_list');
|
||||
return to_assign(0, '还原数据成功');
|
||||
}
|
||||
add_log('delete');
|
||||
return to_assign(0, "删除成功");
|
||||
}
|
||||
if ($this->db->delFile($id)) {
|
||||
add_log('delete');
|
||||
return to_assign(0, "删除成功");
|
||||
} else {
|
||||
return to_assign(1, "备份文件删除失败,请检查文件权限");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}else{
|
||||
$data = array('part' => $part, 'start' => $start[0],'time' => $time);
|
||||
if($start[1]){
|
||||
$rate = floor(100 * ($start[0] / $start[1]));
|
||||
return to_assign(0, "正在还原...卷{$part} ({$rate}%),请勿关闭当前页面",$data);
|
||||
} else {
|
||||
$data['gz'] = 1;
|
||||
return to_assign(0, "正在还原...卷{$part},请勿关闭当前页面",$data);
|
||||
}
|
||||
return to_assign(0, "正在还原...卷{$part},请勿关闭当前页面");
|
||||
}
|
||||
}else{
|
||||
return to_assign(1, "参数错误");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 删除备份文件
|
||||
*/
|
||||
public function del($time = 0,$lock=0){
|
||||
$db= new Backup();
|
||||
if($lock==1){
|
||||
$fileinfo =$db->getFile();
|
||||
$lock = "{$fileinfo['filepath']}backup.lock";
|
||||
if(is_file($lock)){
|
||||
$time = file_get_contents($lock);
|
||||
unlink($lock);
|
||||
}
|
||||
}
|
||||
if($db->delFile((int)$time)){
|
||||
add_log('delete');
|
||||
return to_assign(0, '删除成功');
|
||||
}else{
|
||||
return to_assign(0, '删除失败,请检查权限');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 下载备份文件
|
||||
*/
|
||||
public function downfile($time = 0,$part=0){
|
||||
$db= new Backup();
|
||||
add_log('down');
|
||||
$db->downloadFile((int)$time,$part-1);
|
||||
}
|
||||
|
||||
}
|
@ -5,10 +5,10 @@
|
||||
<table cellspacing="0" cellpadding="0" border="0" class="layui-table">
|
||||
<tr style="background-color: #f5f5f5; text-align: center;">
|
||||
<th style=" text-align: center; font-weight: 800;"><span>文件名称</span></th>
|
||||
<th style=" text-align: center; font-weight: 800;"><span>分卷</span></th>
|
||||
<th style=" text-align: center; font-weight: 800;"><span>文件大小</span></th>
|
||||
<th style=" text-align: center; font-weight: 800;"><span>文件格式</span></th>
|
||||
<th style=" text-align: center; font-weight: 800;"><span>分隔符</span></th>
|
||||
<th style=" text-align: center; font-weight: 800;"><span>文件总大小</span></th>
|
||||
<th style=" text-align: center; font-weight: 800;"><span>分卷总数</span></th>
|
||||
<th style=" text-align: center; font-weight: 800; width:222px"><span>操作</span></th>
|
||||
</tr>
|
||||
{empty name="list"}
|
||||
@ -18,26 +18,32 @@
|
||||
{/empty}
|
||||
{volist name="list" id="vo" key="k"}
|
||||
<tr style="background-color: #fafafa;">
|
||||
<td colspan="6"><strong>备份时间:{$vo.time}</strong></td>
|
||||
</tr>
|
||||
{volist name="vo.data" id="voo"}
|
||||
<tr>
|
||||
<td>
|
||||
{:date("Ymd",$voo.time)}{$voo.compress}{:date("His",$voo.time)}{$voo.compress}{$voo.part}.sql
|
||||
</td>
|
||||
<td align="center"><span>{$voo.part}</span></td>
|
||||
<td align="center"><span>{:format_bytes($voo.size)}</span></td>
|
||||
<td><strong>备份时间:{$vo.time}</strong>{if $vo.timespan == $lock_time}<span style="color:red; margin-left:20px;">该备份不是完整备份,请删除重新备份</span>{/if}</td>
|
||||
<td align="center"><span>.sql</span></td>
|
||||
<td align="center"><span>{$voo.compress}</span></td>
|
||||
<td align="center"><span>{$vo.data.compress}</span></td>
|
||||
<td align="center"><span>{:format_bytes($vo.data.size)}</span></td>
|
||||
<td align="center"><span>{$vo.data.part}</span></td>
|
||||
<td align="center">
|
||||
<div class="layui-btn-group" data-id='{$voo.time}'>
|
||||
<div class="layui-btn-group" data-time='{$vo.timespan}'>
|
||||
{if $vo.timespan == $lock_time}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="reset">清除不完整的备份</a>
|
||||
{else/}
|
||||
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="import">数据还原</a>
|
||||
<a class="layui-btn layui-btn-xs" href='/admin/database/downfile?name={:date("Ymd",$voo.time)}{$voo.compress}{:date("His",$voo.time)}{$voo.compress}{$voo.part}.sql'>备份下载</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">备份删除</a>
|
||||
{/if}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
{for start="0" end="$vo.data.part" step="1"}
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
{:date("Ymd",$vo.timespan)}{$vo.data.compress}{:date("His",$vo.timespan)}{$vo.data.compress}{$i+1}.sql
|
||||
</td>
|
||||
<td align="center">
|
||||
<a class="layui-btn layui-btn-xs" href='/admin/database/downfile?time={$vo.data.time}&part={$i+1}'>下载备份(分卷{$i+1})</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/for}
|
||||
{/volist}
|
||||
</table>
|
||||
</div>
|
||||
@ -49,44 +55,93 @@
|
||||
{block name="script"}
|
||||
<script>
|
||||
function init(layui) {
|
||||
var table = layui.table,
|
||||
form = layui.form;
|
||||
function importData(data){
|
||||
if(data.code==0){
|
||||
console.log(data.msg);
|
||||
layer.closeAll();
|
||||
layer.msg(data.msg,{time: 200000});
|
||||
if($.isPlainObject(data.data)){
|
||||
$.ajax({
|
||||
url: "/admin/database/import",
|
||||
type:'get',
|
||||
data:{"part" : data.data.part, "start" : data.data.start,time:data.data.time},
|
||||
success: function (res) {
|
||||
importData(res);
|
||||
}
|
||||
})
|
||||
}else {
|
||||
layer.msg(data.msg);
|
||||
window.onbeforeunload = function(){ return null; }
|
||||
}
|
||||
} else {
|
||||
layer.msg(data.msg);
|
||||
}
|
||||
}
|
||||
//监听行工具事件
|
||||
$('[lay-event="import"]').on('click',function(){
|
||||
var id=$(this).parent().data('id');
|
||||
var time=$(this).parent().data('time');
|
||||
layer.confirm('确认要还原该备份吗?', {
|
||||
icon: 3,
|
||||
title: '提示'
|
||||
}, function (index) {
|
||||
layer.msg("数据还原中...");
|
||||
layer.msg("数据还原中...",{time: 200000});
|
||||
$.ajax({
|
||||
url: "/admin/database/import?id="+id,
|
||||
url: "/admin/database/import?time="+time,
|
||||
type:'get',
|
||||
success: function (res) {
|
||||
layer.msg(res.msg);
|
||||
importData(res);
|
||||
}
|
||||
})
|
||||
layer.close(index);
|
||||
});
|
||||
window.onbeforeunload = function(){ return "正在还原数据库,请不要关闭!" }
|
||||
layer.close(index);
|
||||
});
|
||||
return false;
|
||||
})
|
||||
|
||||
$('[lay-event="del"]').on('click',function(){
|
||||
var id=$(this).parent().data('id');
|
||||
var time=$(this).parent().data('time');
|
||||
layer.confirm('确认要删除该备份吗?', {
|
||||
icon: 3,
|
||||
title: '提示'
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "/admin/database/del",
|
||||
data: {'id':id},
|
||||
data: {'time':time},
|
||||
success: function (res) {
|
||||
layer.msg(res.msg);
|
||||
if (res.code == 0) {
|
||||
location.reload();
|
||||
setTimeout(function(){
|
||||
location.reload();
|
||||
},2000)
|
||||
}
|
||||
}
|
||||
})
|
||||
layer.close(index);
|
||||
});
|
||||
return false;
|
||||
})
|
||||
|
||||
$('[lay-event="reset"]').on('click',function(){
|
||||
var time=$(this).parent().data('time');
|
||||
layer.confirm('确认要清除该备份吗?', {
|
||||
icon: 3,
|
||||
title: '提示'
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "/admin/database/del",
|
||||
data: {'time':time,'lock':1},
|
||||
success: function (res) {
|
||||
layer.msg(res.msg);
|
||||
if (res.code == 0) {
|
||||
setTimeout(function(){
|
||||
location.reload();
|
||||
},2000)
|
||||
}
|
||||
}
|
||||
})
|
||||
layer.close(index);
|
||||
});
|
||||
return false;
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
@ -2,18 +2,19 @@
|
||||
<!-- 主体 -->
|
||||
{block name="body"}
|
||||
<div class="body-table">
|
||||
<table class="layui-hide" id="test" lay-filter="test"></table>
|
||||
<table class="layui-hide" id="backup" lay-filter="test"></table>
|
||||
</div>
|
||||
<script type="text/html" id="toolbarDemo">
|
||||
<div class="layui-btn-group">
|
||||
<span class="layui-btn layui-btn-sm layui-btn-normal" lay-event="backup">数据备份</span><span class="layui-btn layui-btn-sm" lay-event="optimize">数据优化</span><span class="layui-btn layui-btn-danger layui-btn-sm" lay-event="repair">数据修复</span>
|
||||
<span class="layui-btn layui-btn-sm layui-btn-normal" lay-event="backup">数据备份</span><span class="layui-btn layui-btn-sm" lay-event="optimize">数据表优化</span><span class="layui-btn layui-btn-danger layui-btn-sm" lay-event="repair">数据表修复</span>
|
||||
</div>
|
||||
<span id="dataTips" style="font-size:12px; margin-left:10px"></span>
|
||||
</script>
|
||||
|
||||
{/block}
|
||||
<!-- /主体 -->
|
||||
|
||||
|
||||
<script>
|
||||
<!-- 脚本 -->
|
||||
{block name="script"}
|
||||
<script>
|
||||
@ -22,7 +23,7 @@
|
||||
form = layui.form;
|
||||
|
||||
var tableIns = table.render({
|
||||
elem: '#test',
|
||||
elem: '#backup',
|
||||
title: '数据备份',
|
||||
toolbar: '#toolbarDemo',
|
||||
url: "/admin/database/database", //数据接口
|
||||
@ -34,7 +35,16 @@
|
||||
field: 'name',
|
||||
title: '数据表',
|
||||
width: 220
|
||||
}, {
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '状态',
|
||||
width: 120,
|
||||
templet:function(d){
|
||||
return '<span id="table_'+d.name+'">-</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'engine',
|
||||
title: '存储引擎',
|
||||
align: 'center',
|
||||
@ -75,22 +85,42 @@
|
||||
}
|
||||
});
|
||||
|
||||
//递归备份表
|
||||
function backup(tab,status,table){
|
||||
layer.closeAll();
|
||||
layer.msg("备份中...,请勿关闭本页面",{time: 200000});
|
||||
$.get("/admin/database/backup", tab, function(data){
|
||||
// console.log(data)
|
||||
if(data.code==0){
|
||||
showmsg(data.data.tab.table, data.msg);
|
||||
if(data.data.tab.start=='ok'){
|
||||
layer.msg('备份完成');
|
||||
window.onbeforeunload = function(){ return null }
|
||||
return;
|
||||
}
|
||||
backup(data.data.tab, tab.id != data.data.tab.id);
|
||||
} else {
|
||||
layer.msg('立即备份');
|
||||
}
|
||||
}, "json");
|
||||
}
|
||||
|
||||
//修改备份状态
|
||||
function showmsg(table, msg){
|
||||
console.log(table);
|
||||
$("#table_"+table).addClass('span-color-2').html(msg);
|
||||
}
|
||||
//监听行工具事件
|
||||
table.on('toolbar(test)', function (obj) {
|
||||
var checkData = table.checkStatus(obj.config.id).data;
|
||||
var len = checkData.length;
|
||||
var ids='';
|
||||
var tables=[];
|
||||
if(len==0){
|
||||
layer.msg('请先选择表');
|
||||
return false;
|
||||
}
|
||||
for(var i=0;i<len;i++){
|
||||
if(i==0){
|
||||
ids+=checkData[i].name;
|
||||
}
|
||||
else{
|
||||
ids+=','+checkData[i].name;
|
||||
}
|
||||
tables.push(checkData[i].name);
|
||||
}
|
||||
if (obj.event === 'backup') {
|
||||
layer.confirm('确认要备份选中的'+len+'个数据表吗?', {
|
||||
@ -99,11 +129,30 @@
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "/admin/database/backup",
|
||||
data: {'id':ids},
|
||||
type:'post',
|
||||
data: {'tables':tables},
|
||||
success: function (res) {
|
||||
layer.msg(res.msg);
|
||||
if (res.code == 0) {
|
||||
location.reload();
|
||||
layer.msg( "开始备份,请不要关闭本页面!");
|
||||
window.onbeforeunload = function(){ return "正在备份数据库,请不要关闭!" }
|
||||
backup(res.data.tab);
|
||||
}
|
||||
if (res.code == 2) {
|
||||
layer.confirm('检测到有一个备份任务未完成,请先清除未完成的备份', {
|
||||
icon: 3,
|
||||
title: '提示'
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "/admin/database/del",
|
||||
data: {'lock':1},
|
||||
success: function (res) {
|
||||
layer.msg(res.msg);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
else{
|
||||
layer.msg(res.msg);
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -116,11 +165,13 @@
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "/admin/database/optimize",
|
||||
data: {'id':ids},
|
||||
data: {'tables':tables},
|
||||
success: function (res) {
|
||||
layer.msg(res.msg);
|
||||
if (res.code == 0) {
|
||||
location.reload();
|
||||
setTimeout(function(){
|
||||
location.reload();
|
||||
},2000)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -133,11 +184,13 @@
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: "/admin/database/repair",
|
||||
data: {'id':ids},
|
||||
data: {'tables':tables},
|
||||
success: function (res) {
|
||||
layer.msg(res.msg);
|
||||
if (res.code == 0) {
|
||||
location.reload();
|
||||
setTimeout(function(){
|
||||
location.reload();
|
||||
},2000)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -49,17 +49,13 @@
|
||||
width: 80
|
||||
}, {
|
||||
field: 'content',
|
||||
title: '操作描述',
|
||||
width: 348
|
||||
title: '操作描述'
|
||||
}, {
|
||||
field: 'param_id',
|
||||
title: '操作数据ID',
|
||||
align: 'center',
|
||||
width: 100
|
||||
}, {
|
||||
field: 'param',
|
||||
title: '操作数据'
|
||||
}, {
|
||||
},{
|
||||
field: 'nickname',
|
||||
title: '操作用户',
|
||||
align: 'center',
|
||||
|
@ -1,118 +1,139 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
namespace backup;
|
||||
use think\facade\Db;
|
||||
use think\facade\Config;
|
||||
class Backup
|
||||
{
|
||||
/**
|
||||
* 文件指针
|
||||
* @var resource
|
||||
*/
|
||||
private $fp;
|
||||
|
||||
/**
|
||||
* 备份文件信息 part - 卷号,name - 文件名
|
||||
* @var array
|
||||
*/
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* 当前打开文件大小
|
||||
* @var integer
|
||||
*/
|
||||
private $size = 0;
|
||||
|
||||
/**
|
||||
* 数据库配置
|
||||
* @var integer
|
||||
*/
|
||||
private $dbconfig=array();
|
||||
|
||||
private $dbconfig = array();
|
||||
/**
|
||||
* 备份配置
|
||||
* @var integer
|
||||
*/
|
||||
private $config=array(
|
||||
'path' => './backup/',//数据库备份路径
|
||||
'part' => 20971520,//数据库备份卷大小
|
||||
'compress' => 0,//数据库备份文件是否启用压缩 0不压缩 1 压缩
|
||||
'level' => 9 //数据库备份文件压缩级别 1普通 4 一般 9最高
|
||||
private $config = array(
|
||||
//数据库备份路径
|
||||
'path' => './backup/',
|
||||
//数据库备份卷大小,默认10MB
|
||||
'part' => 10485760,
|
||||
//数据库备份文件是否启用压缩 0不压缩 1 压缩
|
||||
'compress' => 0,
|
||||
//数压缩级别
|
||||
'level' => 9,
|
||||
);
|
||||
/**
|
||||
* 数据库备份构造方法
|
||||
* @param array $file 备份或还原的文件信息
|
||||
* @param array $config 备份配置信息
|
||||
*/
|
||||
public function __construct($config=[]){
|
||||
public function __construct($config = [])
|
||||
{
|
||||
$this->config = array_merge($this->config, $config);
|
||||
//初始化文件名
|
||||
$this->setFile();
|
||||
//初始化数据库连接参数
|
||||
$this->setDbConn();
|
||||
//检查文件是否可写
|
||||
if(!$this->checkPath($this->config['path'])){
|
||||
throw new \Exception("The current directory is not writable");
|
||||
if (!$this->checkPath($this->config['path'])) {
|
||||
throw new \think\Exception("The current directory is not writable");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置脚本运行超时时间
|
||||
* 0表示不限制,支持连贯操作
|
||||
*/
|
||||
public function setTimeout($time=null)
|
||||
{
|
||||
if (!is_null($time)) {
|
||||
set_time_limit($time)||ini_set("max_execution_time", $time);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* 设置数据库连接必备参数
|
||||
* @param array $dbconfig 数据库连接配置信息
|
||||
* @return object
|
||||
* @return object
|
||||
*/
|
||||
public function setDbConn($dbconfig=[])
|
||||
public function setDbConn($dbconfig = [])
|
||||
{
|
||||
if (empty($dbconfig)) {
|
||||
$this->dbconfig = Config::get('database');
|
||||
}else{
|
||||
$this->dbconfig=$dbconfig;
|
||||
$this->dbconfig = Config::get('database');
|
||||
} else {
|
||||
$this->dbconfig = $dbconfig;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* 设置备份文件名
|
||||
* @param String $file 文件名字
|
||||
* @return object
|
||||
* @param Array $file 文件名字
|
||||
* @return object
|
||||
*/
|
||||
public function setFile($file=null)
|
||||
public function setFile($file = null)
|
||||
{
|
||||
if(is_null($file)){
|
||||
$this->file=['name'=>date('Ymd-His'),'part'=>1];
|
||||
}else{
|
||||
if(!array_key_exists("name",$file) && !array_key_exists("part",$file)){
|
||||
$this->file=$file['1'];
|
||||
}else{
|
||||
$this->file=$file;
|
||||
if (is_null($file)) {
|
||||
$this->file = ['name' => date('Ymd-His'), 'part' => 1];
|
||||
} else {
|
||||
if (!array_key_exists("name", $file) && !array_key_exists("part", $file)) {
|
||||
$this->file = $file['1'];
|
||||
} else {
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
//数据类连接
|
||||
public static function connect()
|
||||
{
|
||||
return Db::connect();
|
||||
return \think\facade\Db::connect();
|
||||
}
|
||||
//数据库表列表
|
||||
public function dataList($table = null,$type=1)
|
||||
{
|
||||
$db = self::connect();
|
||||
if (is_null($table)) {
|
||||
$list = $db->query("SHOW TABLE STATUS");
|
||||
} else {
|
||||
if ($type) {
|
||||
$list = $db->query("SHOW FULL COLUMNS FROM {$table}");
|
||||
}else{
|
||||
$list = $db->query("show columns from {$table}");
|
||||
}
|
||||
}
|
||||
return array_map('array_change_key_case', $list);
|
||||
//$list;
|
||||
}
|
||||
|
||||
//数据库备份文件列表
|
||||
public function fileList()
|
||||
{
|
||||
if(!is_dir($this->config['path'])){
|
||||
mkdir($this->config['path'], 0755, true);
|
||||
}
|
||||
$path = realpath($this->config['path']);
|
||||
$flag = \FilesystemIterator::KEY_AS_FILENAME;
|
||||
$glob = new \FilesystemIterator($path, $flag);
|
||||
$list = array();
|
||||
foreach ($glob as $name => $file) {
|
||||
if(preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql(?:\.gz)?$/', $name)){
|
||||
if (!is_dir($this->config['path'])) {
|
||||
mkdir($this->config['path'], 0755, true);
|
||||
}
|
||||
$path = realpath($this->config['path']);
|
||||
$flag = \FilesystemIterator::KEY_AS_FILENAME;
|
||||
$glob = new \FilesystemIterator($path, $flag);
|
||||
$list = array();
|
||||
foreach ($glob as $name => $file) {
|
||||
if (preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql(?:\\.gz)?$/', $name)) {
|
||||
$name1= $name;
|
||||
$name = sscanf($name, '%4s%2s%2s-%2s%2s%2s-%d');
|
||||
|
||||
$date = "{$name[0]}-{$name[1]}-{$name[2]}";
|
||||
$time = "{$name[3]}:{$name[4]}:{$name[5]}";
|
||||
$part = $name[6];
|
||||
|
||||
if(isset($list["{$date} {$time}"])){
|
||||
if (isset($list["{$date} {$time}"])) {
|
||||
$info = $list["{$date} {$time}"];
|
||||
$info['part'] = max($info['part'], $part);
|
||||
$info['size'] = $info['size'] + $file->getSize();
|
||||
@ -120,104 +141,121 @@ class Backup
|
||||
$info['part'] = $part;
|
||||
$info['size'] = $file->getSize();
|
||||
}
|
||||
$extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION));
|
||||
$info['compress'] = ($extension === 'SQL') ? '-' : $extension;
|
||||
$info['time'] = strtotime("{$date} {$time}");
|
||||
|
||||
$extension = strtoupper(pathinfo($file->getFilename(), PATHINFO_EXTENSION));
|
||||
$info['name']=$name1;
|
||||
$info['compress'] = $extension === 'SQL' ? '-' : $extension;
|
||||
$info['time'] = strtotime("{$date} {$time}");
|
||||
$list["{$date} {$time}"] = $info;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
return $list;
|
||||
}
|
||||
public function getFile($type='',$time=0)
|
||||
{ //
|
||||
if(!is_numeric($time) ){
|
||||
throw new \Exception("{$time} Illegal data type");
|
||||
public function getFile($type = '', $time = 0)
|
||||
{
|
||||
//
|
||||
if (!is_numeric($time)) {
|
||||
throw new \think\Exception("{$time} Illegal data type");
|
||||
}
|
||||
switch ($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'time':
|
||||
$time = intval($time);
|
||||
$name = date('Ymd-His', $time) . '-*.sql*';
|
||||
$path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name;
|
||||
$name = date('Ymd-His', $time) . '-*.sql*';
|
||||
$path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name;
|
||||
return glob($path);
|
||||
break;
|
||||
case 'timeverif':
|
||||
$time = intval($time);
|
||||
$name = date('Ymd-His', $time) . '-*.sql*';
|
||||
$path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name;
|
||||
$name = date('Ymd-His', $time) . '-*.sql*';
|
||||
$path = realpath($this->config['path']) . DIRECTORY_SEPARATOR . $name;
|
||||
$files = glob($path);
|
||||
$list = array();
|
||||
foreach($files as $name){
|
||||
$list = array();
|
||||
foreach ($files as $name) {
|
||||
$basename = basename($name);
|
||||
$match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
|
||||
$gz = preg_match('/^\d{8,8}-\d{6,6}-\d+\.sql.gz$/', $basename);
|
||||
$match = sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
|
||||
$gz = preg_match('/^\\d{8,8}-\\d{6,6}-\\d+\\.sql.gz$/', $basename);
|
||||
$list[$match[6]] = array($match[6], $name, $gz);
|
||||
}
|
||||
$last = end($list);
|
||||
if(count($list) === $last[0]){
|
||||
if (count($list) === $last[0]) {
|
||||
return $list;
|
||||
} else {
|
||||
throw new \Exception("File {$files['0']} may be damaged, please check again");
|
||||
throw new \think\Exception("File {$files['0']} may be damaged, please check again");
|
||||
}
|
||||
|
||||
break;
|
||||
case 'pathname':
|
||||
return "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql";
|
||||
break;
|
||||
break;
|
||||
case 'filename':
|
||||
return "{$this->file['name']}-{$this->file['part']}.sql";
|
||||
break;
|
||||
break;
|
||||
case 'filepath':
|
||||
return $this->config['path'];
|
||||
break;
|
||||
default:
|
||||
$arr=array(
|
||||
'pathname'=>"{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql",
|
||||
'filename'=>"{$this->file['name']}-{$this->file['part']}.sql",
|
||||
'filepath'=>$this->config['path'],
|
||||
'file'=>$this->file
|
||||
);
|
||||
return $arr;
|
||||
$arr = array('pathname' => "{$this->config['path']}{$this->file['name']}-{$this->file['part']}.sql", 'filename' => "{$this->file['name']}-{$this->file['part']}.sql", 'filepath' => $this->config['path'], 'file' => $this->file);
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
||||
//删除备份文件
|
||||
public function delFile($time)
|
||||
{
|
||||
if($time){
|
||||
$file=$this->getFile('time',$time);
|
||||
array_map("unlink", $this->getFile('time',$time));
|
||||
if(count( $this->getFile('time',$time) )){
|
||||
throw new \Exception("File {$path} deleted failed");
|
||||
if ($time) {
|
||||
$file = $this->getFile('time', $time);
|
||||
array_map("unlink", $this->getFile('time', $time));
|
||||
if (count($this->getFile('time', $time))) {
|
||||
throw new \think\Exception("File {$path} deleted failed");
|
||||
} else {
|
||||
return $time;
|
||||
return $time;
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("{$time} Time parameter is incorrect");
|
||||
throw new \think\Exception("{$time} Time parameter is incorrect");
|
||||
}
|
||||
}
|
||||
public function import($start){
|
||||
/**
|
||||
* 下载备份
|
||||
* @param string $time
|
||||
* @param integer $part
|
||||
* @return array|mixed|string
|
||||
*/
|
||||
public function downloadFile($time, $part = 0)
|
||||
{
|
||||
$file = $this->getFile('time', $time);
|
||||
$fileName = $file[$part];
|
||||
if (file_exists($fileName)) {
|
||||
ob_end_clean();
|
||||
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Length: ' . filesize($fileName));
|
||||
header('Content-Disposition: attachment; filename=' . basename($fileName));
|
||||
readfile($fileName);
|
||||
} else {
|
||||
throw new \think\Exception("{$time} File is abnormal");
|
||||
}
|
||||
}
|
||||
public function import($start,$time,$part)
|
||||
{
|
||||
//还原数据
|
||||
$db = self::connect();
|
||||
|
||||
if($this->config['compress']){
|
||||
$gz = gzopen($this->file[1], 'r');
|
||||
$db = self::connect();
|
||||
//$this->file=$this->getFile('time',$time);
|
||||
$file = $this->getFile('time', $time);
|
||||
$fileName = $file[$part-1];
|
||||
if (!file_exists($fileName)) {
|
||||
return false;
|
||||
}
|
||||
if ($this->config['compress']) {
|
||||
$gz = gzopen($fileName, 'r');
|
||||
$size = 0;
|
||||
} else {
|
||||
$size = filesize($this->file[1]);
|
||||
$gz = fopen($this->file[1], 'r');
|
||||
$size = filesize($fileName);
|
||||
$gz = fopen($fileName, 'r');
|
||||
}
|
||||
|
||||
$sql = '';
|
||||
if($start){
|
||||
$sql = '';
|
||||
if ($start) {
|
||||
$this->config['compress'] ? gzseek($gz, $start) : fseek($gz, $start);
|
||||
}
|
||||
for($i = 0; $i < 1000; $i++){
|
||||
$sql .= $this->config['compress'] ? gzgets($gz) : fgets($gz);
|
||||
if(preg_match('/.*;$/', trim($sql))){
|
||||
if(false !== $db->execute($sql)){
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$sql .= $this->config['compress'] ? gzgets($gz) : fgets($gz);
|
||||
if (preg_match('/.*;$/', trim($sql))) {
|
||||
if (false !== $db->execute($sql)) {
|
||||
$start += strlen($sql);
|
||||
} else {
|
||||
return false;
|
||||
@ -227,95 +265,71 @@ class Backup
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return array($start, $size);
|
||||
}
|
||||
|
||||
|
||||
//数据库表列表
|
||||
public function dataList($table=null)
|
||||
{
|
||||
$db = self::connect();
|
||||
|
||||
if(is_null($table)){
|
||||
$list = $db->query("SHOW TABLE STATUS");
|
||||
}else{
|
||||
$list = $db->query("show columns from {$table}");
|
||||
}
|
||||
return array_map('array_change_key_case', $list);//$list;
|
||||
}
|
||||
/**
|
||||
* 写入初始数据
|
||||
* @return boolean true - 写入成功,false - 写入失败
|
||||
*/
|
||||
public function Backup_Init(){
|
||||
$sql = "-- -----------------------------\n";
|
||||
public function Backup_Init()
|
||||
{
|
||||
$sql = "-- -----------------------------\n";
|
||||
$sql .= "-- Think MySQL Data Transfer \n";
|
||||
$sql .= "-- \n";
|
||||
$sql .= "-- Host : " .$this->dbconfig['hostname']. "\n";
|
||||
$sql .= "-- Port : " .$this->dbconfig['hostport']. "\n";
|
||||
$sql .= "-- Database : " .$this->dbconfig['database']. "\n";
|
||||
$sql .= "-- \n";
|
||||
$sql .= "-- Part : #{$this->file['part']}\n";
|
||||
$sql .= "-- Date : " . date("Y-m-d H:i:s") . "\n";
|
||||
$sql .= "-- -----------------------------\n\n";
|
||||
$sql .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
|
||||
return $this->write($sql);
|
||||
return $this->write($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份表结构
|
||||
* @param string $table 表名
|
||||
* @param integer $start 起始行数
|
||||
* @return boolean false - 备份失败
|
||||
*/
|
||||
public function backup($table, $start){
|
||||
|
||||
public function backup($table, $start)
|
||||
{
|
||||
$db = self::connect();
|
||||
// 备份表结构
|
||||
if(0 == $start){
|
||||
if (0 == $start) {
|
||||
$result = $db->query("SHOW CREATE TABLE `{$table}`");
|
||||
$sql = "\n";
|
||||
$sql = "\n";
|
||||
$sql .= "-- -----------------------------\n";
|
||||
$sql .= "-- Table structure for `{$table}`\n";
|
||||
$sql .= "-- -----------------------------\n";
|
||||
$sql .= "DROP TABLE IF EXISTS `{$table}`;\n";
|
||||
|
||||
$sql .= trim($result[0]['Create Table']) . ";\n\n";
|
||||
|
||||
if(false === $this->write($sql)){
|
||||
if (false === $this->write($sql)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//数据总数
|
||||
$result = $db->query("SELECT COUNT(*) AS count FROM `{$table}`");
|
||||
|
||||
$count = $result['0']['count'];
|
||||
|
||||
$count = $result['0']['count'];
|
||||
//备份表数据
|
||||
if($count){
|
||||
if ($count) {
|
||||
//写入数据注释
|
||||
if(0 == $start){
|
||||
$sql = "-- -----------------------------\n";
|
||||
if (0 == $start) {
|
||||
$sql = "-- -----------------------------\n";
|
||||
$sql .= "-- Records of `{$table}`\n";
|
||||
$sql .= "-- -----------------------------\n";
|
||||
$this->write($sql);
|
||||
}
|
||||
|
||||
//备份数据记录
|
||||
$result = $db->query("SELECT * FROM `{$table}` LIMIT {$start}, 1000");
|
||||
foreach ($result as $row) {
|
||||
$row = array_map('addslashes', $row);
|
||||
$sql = "INSERT INTO `{$table}` VALUES ('" . str_replace(array("\r","\n"),array('\r','\n'),implode("', '", $row)) . "');\n";
|
||||
if(false === $this->write($sql)){
|
||||
$sql = "INSERT INTO `{$table}` VALUES ('" . str_replace(array("\r", "\n"), array('\\r', '\\n'), implode("', '", $row)) . "');\n";
|
||||
if (false === $this->write($sql)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//还有更多数据
|
||||
if($count > $start + 1000){
|
||||
return array($start + 1000, $count);
|
||||
if ($count > $start + 1000) {
|
||||
//return array($start + 1000, $count);
|
||||
return $this->backup($table, $start + 1000);
|
||||
}
|
||||
}
|
||||
//备份下一表
|
||||
@ -324,81 +338,84 @@ class Backup
|
||||
/**
|
||||
* 优化表
|
||||
* @param String $tables 表名
|
||||
* @return String $tables
|
||||
* @return String $tables
|
||||
*/
|
||||
public function optimize($tables = null){
|
||||
if($tables) {
|
||||
public function optimize($tables = null)
|
||||
{
|
||||
if ($tables) {
|
||||
$db = self::connect();
|
||||
if(is_array($tables)){
|
||||
if (is_array($tables)) {
|
||||
$tables = implode('`,`', $tables);
|
||||
$list = $db->query("OPTIMIZE TABLE `{$tables}`");
|
||||
} else {
|
||||
$list = $db->query("OPTIMIZE TABLE `{$tables}`");
|
||||
}
|
||||
if($list){
|
||||
if ($list) {
|
||||
return $tables;
|
||||
} else {
|
||||
throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!");
|
||||
throw new \think\Exception("data sheet'{$tables}'Repair mistakes please try again!");
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("Please specify the table to be repaired!");
|
||||
throw new \think\Exception("Please specify the table to be repaired!");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 修复表
|
||||
* @param String $tables 表名
|
||||
* @return String $tables
|
||||
* @return String $tables
|
||||
*/
|
||||
public function repair($tables = null){
|
||||
if($tables) {
|
||||
public function repair($tables = null)
|
||||
{
|
||||
if ($tables) {
|
||||
$db = self::connect();
|
||||
if(is_array($tables)){
|
||||
if (is_array($tables)) {
|
||||
$tables = implode('`,`', $tables);
|
||||
$list = $db->query("REPAIR TABLE `{$tables}`");
|
||||
} else {
|
||||
$list = $db->query("REPAIR TABLE `{$tables}`");
|
||||
$list = $db->query("REPAIR TABLE `{$tables}`");
|
||||
}
|
||||
if($list){
|
||||
if ($list) {
|
||||
return $list;
|
||||
} else {
|
||||
throw new \Exception("data sheet'{$tables}'Repair mistakes please try again!");
|
||||
throw new \think\Exception("data sheet'{$tables}'Repair mistakes please try again!");
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("Please specify the table to be repaired!");
|
||||
throw new \think\Exception("Please specify the table to be repaired!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入SQL语句
|
||||
* @param string $sql 要写入的SQL语句
|
||||
* @return boolean true - 写入成功,false - 写入失败!
|
||||
*/
|
||||
private function write($sql){
|
||||
private function write($sql)
|
||||
{
|
||||
$size = strlen($sql);
|
||||
//由于压缩原因,无法计算出压缩后的长度,这里假设压缩率为50%,
|
||||
//一般情况压缩率都会高于50%;
|
||||
$size = $this->config['compress'] ? $size / 2 : $size;
|
||||
$this->open($size);
|
||||
$this->open($size);
|
||||
return $this->config['compress'] ? @gzwrite($this->fp, $sql) : @fwrite($this->fp, $sql);
|
||||
}
|
||||
/**
|
||||
* 打开一个卷,用于写入数据
|
||||
* @param integer $size 写入数据的大小
|
||||
*/
|
||||
private function open($size){
|
||||
if($this->fp){
|
||||
private function open($size)
|
||||
{
|
||||
if ($this->fp) {
|
||||
$this->size += $size;
|
||||
if($this->size > $this->config['part']){
|
||||
if ($this->size > $this->config['part']) {
|
||||
$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
|
||||
$this->fp = null;
|
||||
$this->file['part']++;
|
||||
session('backup_file', $this->file);
|
||||
$this->create();
|
||||
$this->Backup_Init();
|
||||
}
|
||||
} else {
|
||||
$backuppath = $this->config['path'];
|
||||
$filename = "{$backuppath}{$this->file['name']}-{$this->file['part']}.sql";
|
||||
if($this->config['compress']){
|
||||
$filename = "{$backuppath}{$this->file['name']}-{$this->file['part']}.sql";
|
||||
if ($this->config['compress']) {
|
||||
$filename = "{$filename}.gz";
|
||||
$this->fp = @gzopen($filename, "a{$this->config['level']}");
|
||||
} else {
|
||||
@ -426,10 +443,10 @@ class Backup
|
||||
/**
|
||||
* 析构方法,用于关闭文件资源
|
||||
*/
|
||||
public function __destruct(){
|
||||
public function __destruct()
|
||||
{
|
||||
if($this->fp){
|
||||
$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user