tp6用tp5er实现数据库备份,数据库还原
taotaoit ThinkPHP6 2022-02-08 2796 1
关于本站

“最难不过坚持”

本人承接扒站仿站,php网站维护,病毒查杀,网站编辑,网站改版,html制作

有需要网站维护,改版,病毒查杀,网站编辑,网站备案,html制作等相关的工作可以联系我。
本人有多年相关工作经验,也可提供免费咨询,交个朋友。
有需要探讨问题的朋友,也可以加我微信,共同探讨!
微信:15011482830 QQ:408917339

7440786 2655 39
最新评论
https://jueru.net/
评 留言
:weixiao:
评 留言
:shuijiao: :weiqu: :zhenbang: :leng:
评 留言
:yiwen: :yiwen: :yiwen: :yiwen:
评 EasySass: could not generate CSS file. See Output panel for details.
这个业务逻辑多少都有点奇怪了,阅读浏览次数增值在新闻详情页的控制器方法里setInc,这怎么还写进模型事件里了。如果非要用onAfterRead也可以,把新闻文章的内容单独分出来一个news_content表,然后把它和news做关联,然后给news_content表的onAfterRead事件做增值处理,这样点进新闻页内查询到文章内容时才会触发它。
评 TP6模型事件-查询后onAfterRead不好用
文章标签更多
ThinkPHP (254)
Mysql (58)
DedeCms (33)
jQuery (67)
证件照 (1)
setInc (4)
setDec (4)
onclick (5)
打开边栏(ESC) 关闭边栏(ESC)

tp6用tp5er实现数据库备份,数据库还原

composer命令安装:composer require tp5er/tp5-databackup dev-master
安装成功后会在项目文件夹vendor下自动生成数据库备份类库:

安装好之后,里面的test文件夹是案例,但是是tp5的语法,用在tp6上,需要改一下
from clipboard

控制器代码:Database2.php

<?php
namespace app\admin\controller;
use think\facade\Request;
use think\facade\Session;
use \tp5er\Backup;
class Database2 extends Base{
    public function index()
    {
      $db= new Backup();
      return view('index',['list'=>$db->dataList()]);
    }
   //备份文件列表
   public function importlist()
   {
        $db= new Backup();
       return view('importlist',['list'=>$db->fileList()]);
   }
   public function import($time = 0, $part = null, $start = null)
   {
       $db= new Backup();
       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 ZHTReturn('初始化完成!', 1, array('part' => 1, 'start' => 0));
           }else{
               return ZHTReturn('备份文件可能已经损坏,请检查!');
           }
       }else if(is_numeric($part) && is_numeric($start)){

               $list=session::get('backup_list');
               
               $start= $db->setFile($list)->import($start,$time);
              
               if( false===$start){
                     return ZHTReturn('还原数据出错!');
               }elseif(0 === $start){
                   if(isset($list[++$part])){
                       $data = array('part' => $part, 'start' => 0);
                       return ZHTReturn("正在还原...#{$part}", 1, $data);
                   } else {
                       session::delete('backup_list');
                       return ZHTReturn('还原完成!',1);
                   }
               }else{
                   $data = array('part' => $part, 'start' => $start[0]);
                   if($start[1]){
                       $rate = floor(100 * ($start[0] / $start[1]));
                       return ZHTReturn("正在还原...#{$part} ({$rate}%)", 1, $data);
                   } else {
                       $data['gz'] = 1;
                       return ZHTReturn("正在还原...#{$part}", 1, $data);
                   }
                   return ZHTReturn("正在还原...#{$part}", 1);
                   
               }
           
           
       }else{
           return ZHTReturn('参数错误!');
       }

      
   }
   /**
    * 删除备份文件
    */
   public function del($time = 0){
       $db= new Backup();
       if($db->delFile($time)){
        return ZHTReturn("备份文件删除成功!",1);
       }else{
           return ZHTReturn("备份文件删除失败,请检查权限!");
       }
   }
    /**
    * 下载备份文件
    */
   public function down($time = 0){
       $db= new Backup();
       $db->downloadFile($time);
   }

   //备份表
   public function export()
   {
       $db= new Backup();
       if(Request::instance()->isPost()){
           $input=input('post.');
          
           $fileinfo  =$db->getFile();
           //检查是否有正在执行的任务
           $lock = "{$fileinfo['filepath']}backup.lock";
           if(is_file($lock)){
               return ZHTReturn('检测到有一个备份任务正在执行,请稍后再试!');
           } else {
               //创建锁文件
               file_put_contents($lock,time());
           }
           // 检查备份目录是否可写
           if(!is_writeable($fileinfo['filepath'])){
            return ZHTReturn('备份目录不存在或不可写,请检查后重试!');
           }

           //缓存锁文件
           session::set('lock', $lock);
           //缓存备份文件信息
           session::set('backup_file', $fileinfo['file']);
           //缓存要备份的表
           session::set('backup_tables', $input['tables']);
           //创建备份文件
           if(false !== $db->Backup_Init()){
            return ZHTReturn('初始化成功!',1,['tab'=>['id' => 0, 'start' => 0]]);
           }else{
               return ZHTReturn('初始化失败,备份文件创建失败!');
           }
       }else if(Request::instance()->isGet()){
           $tables =  session::get('backup_tables');
           $file=session::get('backup_file');

           $id=input('id');
           $start=input('start');
           $start= $db->setFile($file)->backup($tables[$id], $start);
           if(false === $start){
               return ZHTReturn('备份出错!');
           }else if(0 === $start){
               if(isset($tables[++$id])){
                   $tab = array('id' => $id, 'start' => 0);
                   return ZHTReturn('备份完成!', 1, array('tab' => $tab));
               } else { //备份完成,清空缓存
                   unlink(session::get('lock'));
                   Session::delete('backup_tables');
                   Session::delete('backup_file');
                   return ZHTReturn('备份完成!',1);
               }
           }
       }else{
           return ZHTReturn('参数错误!');
       }


   }

   //修复表
   public function repair($tables= null)
   {
       $db= new Backup();
       if($db->repair($tables)){
        return ZHTReturn("数据表修复完成!",1);
       }else{
           return ZHTReturn("数据表修复出错请重试");
       }
   }
   //优化表
   public function optimize($tables= null)
   {
        $db= new Backup();
         if($db->optimize($tables)){
            return ZHTReturn("数据表优化完成!",1);
         }else{
           return ZHTReturn("数据表优化出错请重试!");
         }
   }
}
数据库备份页面index.html

<link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css" />
<script src="https://www.layuicdn.com/layui/layui.js"></script>

<script>
    layui.use(['jquery','layer'],function(){
      window.$ = layui.$;
      var layer = layui.layer;
      //备份表方法
      $("#export").click(function(){
          $(this).html("正在发送备份请求...");
          $.post(
            $("#export-form").attr("action"),
            $("#export-form").serialize(), 
            function(data){
               
              if(data.status==1){
                $("#export").html( "开始备份,请不要关闭本页面!");
                backup(data.data.tab);
                window.onbeforeunload = function(){ return "正在备份数据库,请不要关闭!" }
              }else{
                 layer.tips(data.msg, "#export", {
                  tips: [1, '#3595CC'],
                  time: 4000
                });
                $("#export").html("立即备份");
              }
              
            }, "json");
            return false;  
      }); 
      //递归备份表
      function backup(tab,status){
        status && showmsg(tab.id, "开始备份...(0%)");
        $.get( $("#export-form").attr("action"), tab, function(data){
          // console.log(data)
                if(data.status==1){
                  showmsg(tab, data.msg);
                  if(!$.isPlainObject(data.data)){
                    $("#export").html("备份完成");
                    window.onbeforeunload = function(){ return null }
                    return;
                  } 

                  backup(data.data.tab, tab.id != data.data.tab.id);
                } else {
                  $("#export").html("立即备份");
                }
            }, "json");

      }
    //修改备份状态
    function showmsg(tab, msg){
       $("table tbody tr").eq(tab.id).find(".info").html(msg)
    }
   
     //优化表
      $("#optimize").click(function(){
           $.post(this.href, $("#export-form").serialize(), function(data){
           
            layer.tips(data.msg, "#optimize", {
              tips: [1, '#3595CC'],
              time: 4000
            });
    
            }, "json");
            return false;    
      });

      //修复表
      $("#repair").on("click",function(e){
         
          $.post(this.href, $("#export-form").serialize(), function(data){
            layer.tips(data.msg, "#repair", {
              tips: [1, '#3595CC'],
              time: 4000
            });
            }, "json");
            return false; 
      });
    });

  </script>

<div class="layui-form">
    <a id="export" class="layui-btn" href="javascript:;" autocomplete="off">立即备份</a>

    <a id="optimize" href="{:url('database2/optimize')}" class="layui-btn ">优化表</a>
    <a id="repair" href="{:url('database2/repair')}" class="layui-btn">修复表</a>
    <a  href="{:url('database2/importlist')}" class="layui-btn">还原数据库</a>
    <form id="export-form" method="post" action="{:url('database2/export')}">
    <table class="layui-table">


      <thead>
        <tr>
            <th width="48"><input class="check-all" checked="checked" type="checkbox" value=""></th>
          <th>表名</th>
          <th>数据量</th>
          <th>数据大小</th>
          <th>创建时间</th>
          <th>备份状态</th>
          <th>操作</th>
        </tr> 
      </thead>
    


  <tbody>
    {foreach name='list' item='table'}   
       <tr>
          <td>
              <input class="ids"  type="checkbox" name="tables[]" value="{$table.name}">
          </td>
          <td>{$table.name}</td>
          <td>{$table.rows}</td>
          <td>{$table.data_length|ZHTFormatBytes}</td>
          <td>{$table.create_time}</td>
          <td class="info">未备份</td>
          <td>
              <a  href="{:url('database2/optimize',['tables'=>$table['name']])}">优化表</a>&nbsp;
              <a  href="{:url('database2/repair',['tables'=>$table['name']])}">修复表</a>
          </td>
        </tr>
    {/foreach}
      </tbody>


    </table>
  </form>
  </div>
数据库还原页面importlist.html

    <link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css" />
    <script src="https://www.layuicdn.com/layui/layui.js"></script>

<div class="layui-form">
   
    <a  class="layui-btn" href="javascript:;" autocomplete="off"> 数据库还原  </a>
    <table class="layui-table">


      <thead>
        <tr>
       
          <th>数据库名称</th>
          <th>卷数</th>
          <th>压缩</th>
          <th>数据大小</th>
          <th>备份时间</th>
          <th>状态</th>
          <th>操作</th>
        </tr> 
      </thead>
    


  <tbody>
    {foreach name='list' item='data'}   
       <tr>

          <td>{$data.time|date='Ymd-His'}</td>
          <td>{$data.part}</td>
          <td>{$data.compress}</td>
          <td>{$data.size|ZHTFormatBytes}</td>
          <td>{$key}</td>
          <td class="status">-</td>
          <td class="action">
             <a class="db-down" href="{:url('database2/down',['time'=>$data['time']])}">下载</a>&nbsp;
              <a class="db-import" href="{:url('database2/import',['time'=>$data['time']])}">还原</a>&nbsp;
              <a class="ajax-get confirm" href="{:url('database2/del',['time'=>$data['time']])}">删除</a>
          </td>
        </tr>
    {/foreach}
      </tbody>
<script>
layui.use(['jquery','layer'],function(){
      window.$ = layui.$;
      var layer = layui.layer;


      $(".db-import").click(function(){
            var self = this, status = ".";

            $(this).parent().prevAll('.status').html("").html('等待还原');

            $.get(self.href, success, "json");
            window.onbeforeunload = function(){ return "正在还原数据库,请不要关闭!" }
            return false;
        
            function success(data){

                if(data.status==1){
                    console.log(data.msg);
                    $(self).parent().prev().text(data.msg);

                    if($.isPlainObject(data.data)){
                        $.get(self.href, 
                            {"part" : data.data.part, "start" : data.data.start}, 
                            success, 
                            "json"
                        );
                        
                    }  else {
                        layer.alert(data.msg);
                        //window.onbeforeunload = function(){ return null; }
                    }
                } else {
                    layer.alert(data.msg);
                }
            }
        });




















    //   $(".db-import").click(function(){
    //     // console.log($(this).parents().find(".status").html() );//正常
    //     // console.log($(this).parent().prevAll('.status').html() );
    //     var statusem=$(this).parent().prevAll('.status');
    //     $(this).parent().prevAll('.status').html("").html('等待还原');
    //     thisobj=this;
    //     $.post(this.href, function(data){
         
    //       if(data.code==1){
    //         // statusem.text(""); // 清空数据
    //         // statusem.append('data'); 
    //         // statusem.text("").append('132');
    //         // $(this).parent().prevAll('.status').html("").html(data.msg);//error :异常原因无法获取当前节点
    //         statusem.html(data.msg);
    //         getdbimport(thisobj,data.data);
    //       }
    //     }, "json");
    //     return false;
    // });



});

</script>

    </table>

  </div>

注意:

有一个问题,如果数据库字段值为null,导出时候就变成了空值'',然后,再还原的话,字段值就变成了0,

如果这个字段是delete_time软删除的话,数据表中所有记录就检索不到了。所以需要改一下,加一个判断,如果字段值为null,则导出的也是null

代码:\vendor\tp5er\tp5-databackup\src\Backup.php 333行

foreach ($result as $row) {
                $arrValues = array();
                foreach($row as $key=>$val){
                    if(is_numeric($val)){
                        $arrValues[]=$val;
                    }else if(is_null($val)){
                        $arrValues[]='NULL';
                    }else{
                        $arrValues[]="'".str_replace(array("\r", "\n"), array('\\r', '\\n'), addslashes($val))."'";
                    }
                }
                $sql = "INSERT INTO `{$table}` VALUES (" . implode(", ", $arrValues) . ");\n";
                if (false === $this->write($sql)) {
                    return false;
                }
            }
截图:

from clipboard


版权声明:本站原创文章,允许自由转载。

相关推荐
tp6控制器不存在的解决方法:控制器不存在:app\controller\Index
ThinkPHP6 | 2021-12-01 6955
当我们下载tp6,应用 多应用模式的时候,提示错误:控制器不存在:app\controller\Index,如图: 原因 多应用没有配置 解决方法 步骤如下: (1)需要安装多应用模式扩展think-multi-app 进入项目根目录。我的路径是(切记改为自己的项目路径):D:\phpStudy\PHPTutorial\...
TP6模型事件-查询后onAfterRead不好用
ThinkPHP6 | 2022-06-15 5644
TP6模型事件-查询后onAfterRead不好用 比如,我想实现浏览新闻后,浏览次数加1 实现: public static function onAfterRead($news) { $news->read_number += 1; $news->save(); } 运行后,浏览次数加1了,很好,对不对...
评论:1条
评论加载中...
发表评论