436 lines
16 KiB
PHP
436 lines
16 KiB
PHP
|
<?php
|
|||
|
|
|||
|
/**
|
|||
|
* @Descripttion : FOXCMS 是一款高效的 PHP 多端跨平台内容管理系统
|
|||
|
* @Author : FoxCMS Team
|
|||
|
* @Date : 2023/6/26 14:43
|
|||
|
* @version : V1.08
|
|||
|
* @copyright : ©2021-现在 贵州黔狐科技股份有限公司 版权所有
|
|||
|
* @LastEditTime : 2023/6/26 14:43
|
|||
|
*/
|
|||
|
|
|||
|
namespace app\admin\controller;
|
|||
|
|
|||
|
use app\admin\util\Basckup;
|
|||
|
use app\admin\util\ModelMg;
|
|||
|
use app\common\controller\AdminBase;
|
|||
|
use think\facade\Db;
|
|||
|
use think\facade\View;
|
|||
|
|
|||
|
class DataBackup extends AdminBase
|
|||
|
{
|
|||
|
private $filterTable = ['fox_admin_log'];
|
|||
|
|
|||
|
public function index($page = 1, $pageSize = 1000)
|
|||
|
{
|
|||
|
if ($this->request->isAjax()) {
|
|||
|
$sql = 'SHOW TABLE STATUS';
|
|||
|
$list = Db::query($sql);
|
|||
|
$rlist = [];
|
|||
|
foreach ($list as $table) {
|
|||
|
$tableName = $table['Name'];
|
|||
|
if (!in_array($tableName, $this->filterTable)) {
|
|||
|
$count = Db::table($tableName)->count();
|
|||
|
$comment = $table['Comment'];
|
|||
|
array_push($rlist, ['name' => $tableName, 'count' => $count, 'comment' => $comment]);
|
|||
|
}
|
|||
|
}
|
|||
|
try {
|
|||
|
$bfday = date("Y-m-d", strtotime("-7 day"));
|
|||
|
\app\common\model\DataBackup::where([['create_time', '<', $bfday]])->delete();
|
|||
|
} catch (\Exception $e) {
|
|||
|
}
|
|||
|
$this->success('查询成功', '', $rlist);
|
|||
|
}
|
|||
|
//SQL命令行
|
|||
|
$safeExcute = \app\common\model\Safe::where(['dict_label' => 'sql_execute'])->find();
|
|||
|
$sql_execute_value = 0;
|
|||
|
if ($safeExcute) {
|
|||
|
$sql_execute_value = $safeExcute['dict_value'];
|
|||
|
}
|
|||
|
View::assign("sql_execute_value", $sql_execute_value); //SQL状态
|
|||
|
return view('index');
|
|||
|
}
|
|||
|
|
|||
|
// 备份
|
|||
|
public function backup()
|
|||
|
{
|
|||
|
$param = $this->request->param();
|
|||
|
$tableName = $param['tableName'];
|
|||
|
if (empty($tableName)) {
|
|||
|
$this->error("备份失败,表名为空");
|
|||
|
}
|
|||
|
$random_num = func_random_num(18);
|
|||
|
$fileName = $tableName . "-" . $random_num . ".sql";
|
|||
|
$content = (new Basckup())->getbackupTable($tableName); //模型表与数据内容
|
|||
|
$time = date('Y-m-d');
|
|||
|
$path = app()->getRootPath() . 'data' . DIRECTORY_SEPARATOR . 'backupdata' . DIRECTORY_SEPARATOR . $time . DIRECTORY_SEPARATOR;
|
|||
|
if (!tp_mkdir($path)) {
|
|||
|
$this->error("创建文件夹失败");
|
|||
|
}
|
|||
|
$fpath = write($path, $fileName, $content); //存入模型字段数据
|
|||
|
if (empty($fpath)) {
|
|||
|
$this->error("备份失败");
|
|||
|
}
|
|||
|
$backup_file = $tableName . ".sql";
|
|||
|
|
|||
|
$dataBackup = new \app\common\model\DataBackup();
|
|||
|
|
|||
|
$cDataBackup = $dataBackup->where(['backup_file' => $time])->find();
|
|||
|
$pid = 0;
|
|||
|
if ($cDataBackup) {
|
|||
|
$pid = $cDataBackup->id;
|
|||
|
} else {
|
|||
|
$dataBackup->save(['pid' => 0, 'backup_file' => $time, 'backup_file_path' => $path, 'table_name' => $time]);
|
|||
|
if (empty($dataBackup->id)) {
|
|||
|
$this->error("操作失败");
|
|||
|
}
|
|||
|
$pid = $dataBackup->id;
|
|||
|
}
|
|||
|
$r = (new \app\common\model\DataBackup())->save(['pid' => $pid, 'backup_file' => $backup_file, 'backup_file_path' => $fpath, 'random_num' => $random_num, 'table_name' => $tableName]);
|
|||
|
if ($r) {
|
|||
|
xn_add_admin_log("备份数据", "backup"); //添加日志
|
|||
|
$this->success('操作成功', "", $fpath);
|
|||
|
} else {
|
|||
|
$this->error("操作失败");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 备份全部文件
|
|||
|
public function backupAll()
|
|||
|
{
|
|||
|
$param = $this->request->param();
|
|||
|
$tableList = json_decode($param['tableList']);
|
|||
|
if (array_key_exists("tableList", $param)) {
|
|||
|
if (sizeof($tableList) <= 0) {
|
|||
|
$this->error("备份失败,参数错误");
|
|||
|
}
|
|||
|
}
|
|||
|
$saveAll = [];
|
|||
|
$time = date('Y-m-d');
|
|||
|
$path = app()->getRootPath() . 'data' . DIRECTORY_SEPARATOR . 'backupdata' . DIRECTORY_SEPARATOR . $time . DIRECTORY_SEPARATOR;
|
|||
|
if (!tp_mkdir($path)) {
|
|||
|
$this->error("创建文件夹失败");
|
|||
|
}
|
|||
|
$dataBackup = new \app\common\model\DataBackup();
|
|||
|
$cDataBackup = $dataBackup->where(['backup_file' => $time])->find();
|
|||
|
$pid = 0;
|
|||
|
if ($cDataBackup) {
|
|||
|
$pid = $cDataBackup->id;
|
|||
|
} else {
|
|||
|
$dataBackup->save(['pid' => 0, 'backup_file' => $time, 'backup_file_path' => $path, 'table_name' => $time]);
|
|||
|
if (empty($dataBackup->id)) {
|
|||
|
$this->error("操作失败");
|
|||
|
}
|
|||
|
$pid = $dataBackup->id;
|
|||
|
}
|
|||
|
|
|||
|
foreach ($tableList as $tableName) {
|
|||
|
$random_num = func_random_num(18);
|
|||
|
$fileName = $tableName . "-" . $random_num . ".sql";
|
|||
|
$content = (new Basckup())->backupTable($tableName); //模型表与数据内容
|
|||
|
$fpath = write($path, $fileName, $content); //存入模型字段数据
|
|||
|
if (empty($fpath)) {
|
|||
|
$this->error("备份失败");
|
|||
|
}
|
|||
|
$backup_file = $tableName . ".sql";
|
|||
|
array_push($saveAll, ['pid' => $pid, 'backup_file' => $backup_file, 'backup_file_path' => $fpath, 'random_num' => $random_num, 'table_name' => $tableName]);
|
|||
|
}
|
|||
|
$rSaveData = (new \app\common\model\DataBackup())->saveAll($saveAll);
|
|||
|
if (sizeof($rSaveData) <= 0) {
|
|||
|
$this->error('操作失败');
|
|||
|
}
|
|||
|
xn_add_admin_log("批量备份数据", "backup"); //添加日志
|
|||
|
$this->success('操作成功', "", $rSaveData);
|
|||
|
}
|
|||
|
|
|||
|
// 数据还原初始化 备份系列
|
|||
|
public function backupIndex()
|
|||
|
{
|
|||
|
$fArr = array();
|
|||
|
$activepath = '/backupdata';
|
|||
|
$basePath = app()->getRootPath() . 'data' . $activepath;
|
|||
|
$arr_file = getDirFile($basePath, $activepath, $fArr);
|
|||
|
$list = [];
|
|||
|
foreach ($arr_file as $ar) {
|
|||
|
if ($ar['filetype'] != "dir2" && $ar['filemine'] == "dir") {
|
|||
|
$rdata['id'] = $ar['filepath'];
|
|||
|
$rdata['backup_file'] = $ar['filename'];
|
|||
|
$creationTime = filectime(replaceSymbol($basePath . $ar['filepath']));
|
|||
|
$rdata['create_time'] = date("Y-m-d H:i:s", $creationTime);
|
|||
|
array_push($list, $rdata);
|
|||
|
}
|
|||
|
}
|
|||
|
$this->success("查询成功", "", $list);
|
|||
|
}
|
|||
|
|
|||
|
// 恢复备份系列
|
|||
|
public function restoreSerie()
|
|||
|
{
|
|||
|
$id = $this->request->param("id");
|
|||
|
if (empty($id)) {
|
|||
|
$this->error("恢复失败,参数错误");
|
|||
|
}
|
|||
|
$basePath = app()->getRootPath() . 'data';
|
|||
|
$sqlFolderPath = replaceSymbol($basePath . $id); //执行模板sql文件
|
|||
|
if (!is_dir($sqlFolderPath)) {
|
|||
|
$this->error("恢复失败,没找到对应恢复数据");
|
|||
|
}
|
|||
|
$files = dirFile($sqlFolderPath);
|
|||
|
if (sizeof($files) > 0) {
|
|||
|
foreach ($files as $file) {
|
|||
|
try {
|
|||
|
$sqlPath = $sqlFolderPath . DIRECTORY_SEPARATOR . $file;
|
|||
|
$sqlContent = @file_get_contents($sqlPath);
|
|||
|
$sqlFormat = (new ModelMg())->sql_split($sqlContent, env('database.prefix', 'fox_'));
|
|||
|
// 执行SQL语句
|
|||
|
$counts = count($sqlFormat);
|
|||
|
for ($i = 0; $i < $counts; $i++) {
|
|||
|
$sql = trim($sqlFormat[$i]);
|
|||
|
if (stristr($sql, 'CREATE TABLE')) {
|
|||
|
Db::execute($sql);
|
|||
|
} else {
|
|||
|
if (trim($sql) == '')
|
|||
|
continue;
|
|||
|
Db::execute($sql);
|
|||
|
}
|
|||
|
}
|
|||
|
} catch (\Exception $e) {
|
|||
|
$this->error("恢复失败,执行sql错误");
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
$this->error("恢复失败");
|
|||
|
}
|
|||
|
$this->success("恢复成功");
|
|||
|
}
|
|||
|
|
|||
|
// 删除备份系列
|
|||
|
public function delRestoreSerie()
|
|||
|
{
|
|||
|
$id = $this->request->param("id");
|
|||
|
if (empty($id)) {
|
|||
|
$this->error("删除失败,参数错误");
|
|||
|
}
|
|||
|
$basePath = app()->getRootPath() . 'data';
|
|||
|
$sqlFolderPath = replaceSymbol($basePath . $id); //执行模板sql文件
|
|||
|
if (!is_dir($sqlFolderPath)) {
|
|||
|
$this->error("恢复失败,没找到对应恢复数据");
|
|||
|
}
|
|||
|
delDir($sqlFolderPath); //删除子文件数据
|
|||
|
$this->success("删除成功");
|
|||
|
}
|
|||
|
|
|||
|
// 删除批量备份系列
|
|||
|
public function delRestoreSeries()
|
|||
|
{
|
|||
|
$param = $this->request->param();
|
|||
|
$idList = json_decode($param['idList']);
|
|||
|
if (array_key_exists("idList", $param)) {
|
|||
|
if (sizeof($idList) <= 0) {
|
|||
|
$this->error("删除失败,参数错误");
|
|||
|
}
|
|||
|
}
|
|||
|
$basePath = app()->getRootPath() . 'data';
|
|||
|
foreach ($idList as $id) {
|
|||
|
$sqlFolderPath = replaceSymbol($basePath . $id); //执行模板sql文件
|
|||
|
if (!is_dir($sqlFolderPath)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
delDir($sqlFolderPath);
|
|||
|
}
|
|||
|
$this->success("删除成功");
|
|||
|
}
|
|||
|
|
|||
|
// 点击备份目录文件
|
|||
|
public function tempFile()
|
|||
|
{
|
|||
|
$param = $this->request->param();
|
|||
|
if ($this->request->isAjax()) {
|
|||
|
$fArr = array();
|
|||
|
$activepath = $param['pid'];
|
|||
|
$basePath = app()->getRootPath() . 'data';
|
|||
|
$basePath1 = replaceSymbol($basePath . $activepath);
|
|||
|
$arr_file = getDirFile($basePath1, $activepath, $fArr);
|
|||
|
$list = [];
|
|||
|
foreach ($arr_file as $ar) {
|
|||
|
if ($ar['filemine'] == "file") {
|
|||
|
$rdata['id'] = $ar['filepath'];
|
|||
|
$rdata['filesize'] = $ar['filesize'];
|
|||
|
$rdata['backup_file'] = $ar['filename'];
|
|||
|
$creationTime = filectime(replaceSymbol($basePath . $ar['filepath']));
|
|||
|
$rdata['create_time'] = date("Y-m-d H:i:s", $creationTime);
|
|||
|
array_push($list, $rdata);
|
|||
|
}
|
|||
|
}
|
|||
|
$this->success("查询成功", "", $list);
|
|||
|
}
|
|||
|
View::assign("pid", $param['id']);
|
|||
|
return view();
|
|||
|
}
|
|||
|
|
|||
|
// 执行命令
|
|||
|
public function executeCommand()
|
|||
|
{
|
|||
|
$command = $this->request->param("command");
|
|||
|
if (empty($command)) {
|
|||
|
$this->error("参数错误");
|
|||
|
}
|
|||
|
$command = trim($command);
|
|||
|
$commands = explode("\n", $command);
|
|||
|
$rlist = [];
|
|||
|
foreach ($commands as $comm) {
|
|||
|
$comm = trim($comm);
|
|||
|
$type = 1; //执行语句
|
|||
|
$msg = "";
|
|||
|
$list = [];
|
|||
|
if (strpos($comm, 'drop') !== false || strpos($comm, 'DROP') !== false) { //不能删除
|
|||
|
$msg = "删除'数据表'或'数据库'的语句不允许在这里执行!";
|
|||
|
} else {
|
|||
|
if (strpos($comm, 'select') !== false || strpos($comm, 'SELECT') !== false) { //查询语句
|
|||
|
try {
|
|||
|
$list = Db::query($comm);
|
|||
|
$rfList = [];
|
|||
|
foreach ($list as $result) {
|
|||
|
$rf = "";
|
|||
|
foreach ($result as $key => $kr) {
|
|||
|
$rf .= $key . "=" . $kr . ";";
|
|||
|
}
|
|||
|
array_push($rfList, $rf);
|
|||
|
}
|
|||
|
$list = $rfList;
|
|||
|
$msg = '成功查询SQL语句!';
|
|||
|
} catch (\Exception $e) {
|
|||
|
$msg = '执行SQL语句失败!';
|
|||
|
}
|
|||
|
$type = 2; //查询语句
|
|||
|
} else { //执行语句
|
|||
|
try {
|
|||
|
$r = Db::execute($comm);
|
|||
|
if ($r) {
|
|||
|
$msg = '成功执行SQL语句!';
|
|||
|
} else {
|
|||
|
$msg = '执行SQL语句无结果!';
|
|||
|
}
|
|||
|
} catch (\Exception $e) {
|
|||
|
$msg = '执行SQL语句失败!';
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
array_push($rlist, ['type' => $type, 'msg' => $msg, 'result' => $list, 'command' => $comm]);
|
|||
|
}
|
|||
|
$this->success("执行成功", '', $rlist);
|
|||
|
}
|
|||
|
|
|||
|
// 删除恢复文件
|
|||
|
public function delRestoreFile()
|
|||
|
{
|
|||
|
$id = $this->request->param("id");
|
|||
|
if (empty($id)) {
|
|||
|
$this->error("删除失败,参数错误");
|
|||
|
}
|
|||
|
$sqlPath = app()->getRootPath() . 'data' . $id;
|
|||
|
if (!file_exists($sqlPath)) {
|
|||
|
$this->error("恢复失败,参数错误");
|
|||
|
}
|
|||
|
$sqlPath = replaceSymbol($sqlPath);
|
|||
|
$r = @unlink($sqlPath);
|
|||
|
if ($r) {
|
|||
|
$this->success("删除成功");
|
|||
|
}
|
|||
|
$this->error("删除失败");
|
|||
|
}
|
|||
|
|
|||
|
// 批量删除恢复文件
|
|||
|
public function delRestoreFiles()
|
|||
|
{
|
|||
|
$param = $this->request->param();
|
|||
|
$idList = json_decode($param['idList']);
|
|||
|
if (array_key_exists("idList", $param)) {
|
|||
|
if (sizeof($idList) <= 0) {
|
|||
|
$this->error("删除失败,参数错误");
|
|||
|
}
|
|||
|
}
|
|||
|
$errorCount = 0;
|
|||
|
$basepath = app()->getRootPath() . 'data';
|
|||
|
foreach ($idList as $id) {
|
|||
|
$sqlPath = replaceSymbol($basepath . $id);
|
|||
|
if (!file_exists($sqlPath)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
$r = @unlink($sqlPath);
|
|||
|
if (!$r) {
|
|||
|
$errorCount++;
|
|||
|
}
|
|||
|
}
|
|||
|
if ($errorCount > 0) {
|
|||
|
$this->error("删除失败");
|
|||
|
}
|
|||
|
$this->success("删除成功");
|
|||
|
}
|
|||
|
|
|||
|
// 恢复数据
|
|||
|
public function restore()
|
|||
|
{
|
|||
|
$id = $this->request->param("id");
|
|||
|
if (empty($id)) {
|
|||
|
$this->error("恢复失败,参数错误");
|
|||
|
}
|
|||
|
$sqlPath = app()->getRootPath() . 'data' . $id;
|
|||
|
if (!file_exists($sqlPath)) {
|
|||
|
$this->error("恢复失败,参数错误");
|
|||
|
}
|
|||
|
$sqlPath = replaceSymbol($sqlPath);
|
|||
|
$sqlContent = @file_get_contents($sqlPath);
|
|||
|
$sqlFormat = (new ModelMg())->sql_split($sqlContent, env('database.prefix', 'fox_'));
|
|||
|
// 执行SQL语句
|
|||
|
$counts = count($sqlFormat);
|
|||
|
for ($i = 0; $i < $counts; $i++) {
|
|||
|
$sql = trim($sqlFormat[$i]);
|
|||
|
if (stristr($sql, 'CREATE TABLE')) {
|
|||
|
Db::execute($sql);
|
|||
|
} else {
|
|||
|
if (trim($sql) == '')
|
|||
|
continue;
|
|||
|
Db::execute($sql);
|
|||
|
}
|
|||
|
}
|
|||
|
$this->success("恢复成功");
|
|||
|
}
|
|||
|
|
|||
|
// 批量恢复数据
|
|||
|
public function restores()
|
|||
|
{
|
|||
|
$param = $this->request->param();
|
|||
|
$idList = json_decode($param['idList']);
|
|||
|
if (array_key_exists("idList", $param)) {
|
|||
|
if (sizeof($idList) <= 0) {
|
|||
|
$this->error("删除失败,参数错误");
|
|||
|
}
|
|||
|
}
|
|||
|
$basepath = app()->getRootPath() . 'data';
|
|||
|
foreach ($idList as $id) {
|
|||
|
$sqlPath = $basepath . $id;
|
|||
|
if (!file_exists($sqlPath)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
$sqlPath = replaceSymbol($sqlPath);
|
|||
|
$sqlContent = @file_get_contents($sqlPath);
|
|||
|
$sqlFormat = (new ModelMg())->sql_split($sqlContent, env('database.prefix', 'fox_'));
|
|||
|
// 执行SQL语句
|
|||
|
$counts = count($sqlFormat);
|
|||
|
for ($i = 0; $i < $counts; $i++) {
|
|||
|
$sql = trim($sqlFormat[$i]);
|
|||
|
if (stristr($sql, 'CREATE TABLE')) {
|
|||
|
Db::execute($sql);
|
|||
|
} else {
|
|||
|
if (trim($sql) == '')
|
|||
|
continue;
|
|||
|
Db::execute($sql);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$this->success("恢复成功");
|
|||
|
}
|
|||
|
}
|