153 lines
6.1 KiB
PHP
153 lines
6.1 KiB
PHP
|
<?php
|
|||
|
namespace app\controller\manager;
|
|||
|
|
|||
|
use think\facade\{Db, Config, Env};
|
|||
|
use app\model\{Log as MLog};
|
|||
|
use app\service\Tool;
|
|||
|
|
|||
|
class Backup extends Base
|
|||
|
{
|
|||
|
/**
|
|||
|
* 因受mysql 配置参数net_buffer_length和max_allowed_packet大小的限制,因此insert语句改为单条插入
|
|||
|
* show VARIABLES like "%net_buffer_length%" 默认单条sql语句长度16k
|
|||
|
* show VARIABLES like "%max_allowed_packet%" 默认单个sql文件最大容量
|
|||
|
* sql 文件注释 -- + 空格之后填写注释内容
|
|||
|
* 因根目录文件夹权限限制,因此需要手动创建backup/data目录并赋予权限(www用户组)
|
|||
|
*/
|
|||
|
public function back()
|
|||
|
{
|
|||
|
ini_set('max_execution_time', 0);
|
|||
|
ini_set("memory_limit",-1);
|
|||
|
set_time_limit(0);
|
|||
|
|
|||
|
$path = Config::get('filesystem.disks.backup.root') . '/';
|
|||
|
$dataBase = Env::get('database.database');
|
|||
|
// 不要使用单引号,双引号中的变量可以解析,单引号就是绝对的字符串
|
|||
|
$eol = "\r\n";
|
|||
|
$eolB = "\r\n\r\n";
|
|||
|
$info = '-- ------------------------------'.$eol;
|
|||
|
$info .= '-- 日期: '.date('Y-m-d H:i:s',time()).$eol;
|
|||
|
$info .= '-- MySQL --Database - '.$dataBase.$eol;
|
|||
|
$info .= '-- ------------------------------'.$eol;
|
|||
|
|
|||
|
$info .= 'CREATE DATABASE IF NOT EXISTS `'.$dataBase.'` DEFAULT CHARACTER SET "utf8mb4" COLLATE "utf8mb4_general_ci";'.$eolB;
|
|||
|
$info .= 'USE `'.$dataBase.'`;'.$eol;
|
|||
|
|
|||
|
if(is_dir($path)) {
|
|||
|
if(!is_writable($path)) {
|
|||
|
chmod($path, 0755);
|
|||
|
}
|
|||
|
} else {
|
|||
|
mkdir($path, 0755, true);
|
|||
|
}
|
|||
|
$fileName = $path.$dataBase.'_'.date('YmdHis',time()).'.sql';
|
|||
|
if(file_exists($fileName)) {
|
|||
|
@unlink($fileName);
|
|||
|
}
|
|||
|
// 以追加的方式写入
|
|||
|
file_put_contents($fileName, $info, FILE_APPEND);
|
|||
|
$tables = Db::query('show tables');
|
|||
|
foreach ($tables as $table) {
|
|||
|
// 表结构
|
|||
|
$tableName = $table['Tables_in_'.$dataBase];
|
|||
|
$sqlTable = 'SHOW CREATE TABLE '.$tableName;
|
|||
|
$res = Db::query($sqlTable);
|
|||
|
$infoTable = '-- ------------------------------'.$eol;
|
|||
|
$infoTable .= '-- Table structure for `'.$tableName.'`'.$eol;
|
|||
|
$infoTable .= '-- ------------------------------'.$eolB;
|
|||
|
$infoTable .= 'DROP TABLE IF EXISTS `'.$tableName.'`;'.$eolB;
|
|||
|
$infoTable .= $res[0]['Create Table'].';'.$eolB;
|
|||
|
// 表数据
|
|||
|
$infoTable .= '-- ------------------------------'.$eol;
|
|||
|
$infoTable .= '-- Data for the table `'.$tableName.'`'.$eol;
|
|||
|
$infoTable .= '-- ------------------------------'.$eolB;
|
|||
|
file_put_contents($fileName, $infoTable, FILE_APPEND);
|
|||
|
|
|||
|
$sqlData = 'select * from '.$tableName;
|
|||
|
$data = Db::query($sqlData);
|
|||
|
$count = count($data);
|
|||
|
if ($count > 0) {
|
|||
|
$dataStr = 'INSERT INTO `'.$tableName.'` VALUE ';
|
|||
|
foreach ($data as $k => $item) {
|
|||
|
$valStr = '(';
|
|||
|
foreach ($item as $val) {
|
|||
|
// 字符串转义
|
|||
|
$val = addslashes($val);
|
|||
|
$valStr .= '"'.$val.'", ';
|
|||
|
}
|
|||
|
// 去除最后的逗号和空格
|
|||
|
$valStr = substr($valStr,0,strlen($valStr)-2);
|
|||
|
// 限制单条sql语句在16K以内(可根据mysql配置条件进行调整)
|
|||
|
$sqlLength = strlen($dataStr) + strlen($valStr);
|
|||
|
if($sqlLength >= (1024 * 16 - 10)) {
|
|||
|
$dataStr .= $valStr.');'.$eol;
|
|||
|
file_put_contents($fileName, $dataStr, FILE_APPEND);
|
|||
|
// 提前分段写入后需重置数据语句
|
|||
|
if ($k <= ($count-1)) {
|
|||
|
$dataStr = 'INSERT INTO `'.$tableName.'` VALUE ';
|
|||
|
} else {
|
|||
|
$dataStr = '';
|
|||
|
}
|
|||
|
} else {
|
|||
|
if ($k < ($count-1)) {
|
|||
|
$dataStr .= $valStr.'),'.$eol;
|
|||
|
} else {
|
|||
|
$dataStr .= $valStr.');'.$eolB;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
file_put_contents($fileName, $dataStr, FILE_APPEND);
|
|||
|
}
|
|||
|
}
|
|||
|
clearstatcache();
|
|||
|
|
|||
|
$backups = explode('/', $fileName);
|
|||
|
$backupName = $backups[count($backups)-1];
|
|||
|
$src = Config::get('filesystem.disks.backup.url') . '/';
|
|||
|
return $this->json(0, '备份成功:' . $src . $backupName);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public function index()
|
|||
|
{
|
|||
|
$path = Config::get('filesystem.disks.backup.root') . '/';
|
|||
|
$src = Config::get('filesystem.disks.backup.url') . '/';
|
|||
|
$items = [];
|
|||
|
if(is_dir($path)) {
|
|||
|
if(!is_readable($path)) {
|
|||
|
chmod($path,0755);
|
|||
|
}
|
|||
|
$files = scandir($path);
|
|||
|
foreach ($files as $file) {
|
|||
|
if($file != '.' && $file != '..') {
|
|||
|
$ext = substr($file, -4);
|
|||
|
if ($ext == '.sql') {
|
|||
|
$creatTime = substr($file, -18, 14);
|
|||
|
$items[] = [
|
|||
|
'file' => $file,
|
|||
|
'path' => $src . $file,
|
|||
|
'time' =>is_numeric($creatTime) ? date('Y-m-d H:i:s', strtotime($creatTime)) : '',
|
|||
|
];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
clearstatcache();
|
|||
|
|
|||
|
$this->data['items'] = $items;
|
|||
|
$this->data['backupPath'] = str_replace('\\','/', $path);
|
|||
|
return $this->view();
|
|||
|
}
|
|||
|
|
|||
|
public function del()
|
|||
|
{
|
|||
|
if (request()->isPost()) {
|
|||
|
$filePath = input('post.id');
|
|||
|
Tool::delFile($filePath);
|
|||
|
MLog::write('backup', 'del', '删除了备份数据文件,文件路径为:' . $filePath);
|
|||
|
return $this->json();
|
|||
|
} else {
|
|||
|
return $this->json(1, '非法请求');
|
|||
|
}
|
|||
|
}
|
|||
|
}
|