$v) {
$dbtables[$k]['size'] = format_bytes($v['Data_length'] + $v['Index_length']);
$total += $v['Data_length'] + $v['Index_length'];
}
$this->assign('list', $dbtables);
$this->assign('total', format_bytes($total));
$this->assign('tableNum', count($dbtables));
return $this->fetch('',getAdmStoId());
}
public function backup(){
@ini_set('memory_limit', '1024M');
//防止备份数据过程超时
function_exists('set_time_limit') && set_time_limit(0);
// send_http_status('310');
$tables = I('tables/a', array());
if (empty($tables)) {
$this->error('请选择要备份的数据表');
}
$time = time();//开始时间
// 检查存储目录不存在则创建
if(!file_exists(UPLOAD_PATH.'sqldata')){
mkdir(UPLOAD_PATH.'sqldata');
}
$path = UPLOAD_PATH."sqldata/tpshop_tables_" . date("Ymd").get_rand_str(3,0);
$pre = "# -----------------------------------------------------------\n";
$sqlNo = "# Description:备份的数据表[结构]:" . implode(",", $tables) . "\n";
//取得表结构信息
//1,表示表名和字段名会用``包着的,0 则不用``
DB::execute("SET SQL_QUOTE_SHOW_CREATE = 1");
foreach ($tables as $table) {
$sqlTable.="# 表的结构 {$table} \n";
$sqlTable .= "DROP TABLE IF EXISTS `{$table}`;\n";
$tmp = DB::query("SHOW CREATE TABLE {$table}");
$sqlTable .= $tmp[0]['Create Table'] . " ;\n\n";
}
$file_str = $pre . $sqlNo . $sqlTable . $outstr;
$file = $path . "_1". ".sql";
if (!file_put_contents($file, $file_str, FILE_APPEND)) {
$this->error("备份文件写入失败!", U('Tools/index'));
}
$outstr = ""; // 转存变量后 这里又清空了
$file_n = 2; // 第几个sql 文件
$backedTable = array(); // 已经备份了哪些表
//表中的数据
foreach ($tables as $table) {
$backedTable[] = $table;
$outstr.="\n\n# 转存表中的数据:{$table} \n";
$tableInfo = DB::query("SHOW TABLE STATUS LIKE '{$table}'");
$pagesize = 10000;
$page = ceil($tableInfo[0]['Rows'] / $pagesize); // 算一下有多少页
// 组装每一页的 insert 语句
for ($i = 1; $i <= $page; $i++) {
$offset = ($i-1) * $pagesize; // 起始位置
$query = DB::query("SELECT * FROM {$table} LIMIT $offset, $pagesize");
$insertSql = "";
foreach ($query as $val) {
$temSql = ""; // 当前这一页的插入语句
$tn = 0;
foreach ($val as $v) { // 每一行没一个字段的语句拼装
$temSql.=$tn == 0 ? "" : ",";
$temSql.=$v == '' ? "''" : "'{$v}'";
$tn++;
}
$insertSql .= "INSERT INTO `{$table}` VALUES ({$temSql});\n";
}
$sqlNo = "\n# Time: " . date("Y-m-d H:i:s") . "\n" .
"# -----------------------------------------------------------\n" .
"# SQLFile Label:#{$file_n}\n# -----------------------------------------------------------\n\n\n";
$sqlNo .= "# Description:备份的数据表[数据]:" . $table . $sqlNo;
$path = UPLOAD_PATH."sqldata/tpshop_{$table}_" . date("Ymd").get_rand_str(3,0);
$file = $path . "_" . $file_n . ".sql";
$outstr = $pre . $sqlNo . $outstr.$insertSql;
if (!file_put_contents($file, $outstr, FILE_APPEND)) {
$this->error("备份文件写入失败!", U('Tools/index'));
}
$outstr = "";
$backedTable = array();
$backedTable[] = $table;
$file_n++;
}
}
$time = time() - $time;
exit(json_encode(array('status'=>1,'msg'=>"成功备份数据表,本次备份共生成了" . ($file_n-1) . "个SQL文件。耗时:{$time} 秒")));
}
public function restore(){
$size = 0;
$pattern = "*.sql";
$filelist = glob(UPLOAD_PATH."sqldata/".$pattern);
$fileArray = array();
foreach ($filelist as $i => $file) {
//只读取文件
if (is_file($file)) {
$_size = filesize($file);
$size += $_size;
$name = basename($file);
$pre = substr($name, 0, strrpos($name, '_'));
$number = str_replace(array($pre. '_', '.sql'), array('', ''), $name);
$fileArray[] = array(
'name' => $name,
'pre' => $pre,
'time' => filemtime($file),
'size' => $_size,
'number' => $number,
);
}
}
if(empty($fileArray)) $fileArray = array();
krsort($fileArray); //按备份时间倒序排列
$this->assign('vlist', $fileArray);
$this->assign('total', format_bytes($size));
$this->assign('filenum', count($fileArray));
return $this->fetch('',getAdmStoId());
}
/**
* 读取要导入的sql文件列表并排序后插入SESSION中
*/
private function getRestoreFiles() {
$sqlfilepre = I('sqlfilepre','');//获取sql文件前缀 tpshop_tp_article_cat_20170206pno_4.sql.html
if (empty($sqlfilepre)) {
$this->error('请选择要还原的数据文件!');
}
$pattern = $sqlfilepre. "*.sql";
$sqlFiles = glob(UPLOAD_PATH."sqldata/".$pattern);
if (empty($sqlFiles)) {
$this->error('不存在对应的SQL文件!');
}
//将要还原的sql文件按顺序组成数组,防止先导入不带表结构的sql文件
$files = array();
foreach ($sqlFiles as $sqlFile) {
$sqlFile = basename($sqlFile);
$k = str_replace(".sql", "", str_replace($sqlfilepre . "_", "", $sqlFile));
$files[$k] = $sqlFile;
}
unset($sqlFiles, $sqlfilepre);
ksort($files);
return $files;
}
/**
* 执行还原数据库操作
*/
public function restoreData() {
@ini_set('memory_limit', '1024M');
function_exists('set_time_limit') && set_time_limit(0); //防止备份数据过程超时
//取得需要导入的sql文件
if (!isset($_SESSION['cacheRestore']['files'])) {
$_SESSION['cacheRestore']['starttime'] = time();
$_SESSION['cacheRestore']['files'][] = I('sqlfilepre','');//$this->getRestoreFiles();
}
$files = $_SESSION['cacheRestore']['files'];
if (empty($files)) {
unset($_SESSION['cacheRestore']);
$this->error('不存在对应的SQL文件');
}
//取得上次文件导入到sql的句柄位置
$position = isset($_SESSION['cacheRestore']['position']) ? $_SESSION['cacheRestore']['position'] : 0;
$execute = 0;
foreach ($files as $fileKey => $sqlFile) {
$file = UPLOAD_PATH."sqldata/". $sqlFile;
if (!file_exists($file))
continue;
$file = fopen($file, "r");
$sql = "";
fseek($file, $position); //将文件指针指向上次位置
while (!feof($file)) {
$tem = trim(fgets($file));
//过滤,去掉空行、注释行(#,--)
if (empty($tem) || $tem[0] == '#' || ($tem[0] == '-' && $tem[1] == '-'))
continue;
//统计一行字符串的长度
$end = (int) (strlen($tem) - 1);
//检测一行字符串最后有个字符是否是分号,是分号则一条sql语句结束,否则sql还有一部分在下一行中
if ($tem[$end] == ";") {
$sql .= $tem;
DB::execute($sql);
$sql = "";
$execute++;
if ($execute > 500) {
$_SESSION['cacheRestore']['position'] = ftell($file);
$imported = isset($_SESSION['cacheRestore']['imported']) ? $_SESSION['cacheRestore']['imported'] : 0;
$imported += $execute;
$_SESSION['cacheRestore']['imported'] = $imported;
//echo json_encode(array("status" => 1, "info" => '如果导入SQL文件卷较大(多)导入时间可能需要几分钟甚至更久,请耐心等待导入完成,导入期间请勿刷新本页,当前导入进度:已经导入' . $imported . '条Sql', "url" => U('Database/restoreData', array(get_randomstr(5) => get_randomstr(5)))));
$this->success('如果SQL文件卷较大(多),则可能需要几分钟甚至更久,
请耐心等待完成,请勿刷新本页,
当前导入进度:已经导入' . $imported . '条Sql', U('Tools/restoreData', array(get_rand_str(5,0) => get_rand_str(5,0))));
exit();
}
} else {
$sql .= $tem;
}
}
//错误位置结束
fclose($file);
unset($_SESSION['cacheRestore']['files'][$fileKey]);
$position = 0;
}
$time = time() - $_SESSION['cacheRestore']['starttime'];
unset($_SESSION['cacheRestore']);
$this->success("导入成功,耗时:{$time} 秒钟", U('Tools/restore'));
}
/**
* 优化
*/
public function optimize() {
$batchFlag = I('get.batchFlag', 0, 'intval');
//批量删除
if ($batchFlag) {
$table = I('key', array());
}else {
$table[] = I('tablename' , '');
}
if (empty($table)) {
$this->error('请选择要优化的表');
}
$strTable = implode(',', $table);
if (!DB::query("OPTIMIZE TABLE {$strTable} ")) {
$strTable = '';
}
$this->success("优化表成功" . $strTable, U('Tools/index'));
}
/**
* 修复
*/
public function repair() {
$batchFlag = I('get.batchFlag', 0, 'intval');
//批量删除
if ($batchFlag) {
$table = I('key', array());
}else {
$table[] = I('tablename' , '');
}
if (empty($table)) {
$this->error('请选择修复的表');
}
$strTable = implode(',', $table);
if (!DB::query("REPAIR TABLE {$strTable} ")) {
$strTable = '';
}
$this->success("修复表成功" . $strTable, U('Tools/index'));
}
public function restoreUpload()
{
$file = request()->file('sqlfile');
// 移动到框架应用根目录/public/uploads/ 目录下
$save_url = 'public/upload/sqldata';
$info = $file->validate(['size'=>100000000,'ext'=>'sql',])->move($save_url,'');
if($info){
if (file_exists($save_url.'/'.$info->getFilename)) {
$this->success("上传成功", U('Tools/restore'));
} else {
$this->error('文件不存在');
}
}else{
// 上传失败获取错误信息
$this->error($file->getError());
}
}
/**
* 下载
*/
public function downFile() {
$file = $this->request->param('file');
$type = $this->request->param('type');
if (empty($file) || empty($type) || !in_array($type, array("zip", "sql"))) {
$this->error("下载地址不存在");
}
$path = array("zip" => UPLOAD_PATH."zipdata/", "sql" => UPLOAD_PATH."sqldata/");
$filePath = $path[$type] . $file;
if (!file_exists($filePath)) {
$this->error("该文件不存在,可能是被删除");
}
$filename = basename($filePath);
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $filename . '"');
header("Content-Length: " . filesize($filePath));
readfile($filePath);
}
/**
* 删除sql文件
*/
public function delSqlFiles() {
$batchFlag = I('get.batchFlag', 0, 'intval');
//批量删除
if ($batchFlag) {
$files = I('key', array());
}else {
$files[] = I('sqlfilename' , '');
}
if (empty($files)) {
$this->error('请选择要删除的sql文件');
}
foreach ($files as $file) {
$a = unlink(UPLOAD_PATH."sqldata". '/' . $file);
}
if($a){
$this->success("已删除:" . implode(",", $files), U('Tools/restore'));
}else{
$this->error("删除失败:" . implode(",", $files), U('Tools/restore'));
}
}
public function region(){
$parent_id = I('parent_id',0);
if($parent_id == 0){
$parent = array('id'=>0,'name'=>"中国省份地区",'level'=>0);
}else{
$parent = M('region')->where("id=$parent_id")->find();
}
$region = M('region')->where("parent_id=$parent_id")->select();
$this->assign('parent',$parent);
$this->assign('region',$region);
return $this->fetch('',getAdmStoId());
}
public function regionHandle(){
$data = I('post.');
$id = I('id');
$referurl = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : U("Tools/region");
if(empty($id)){
$data['level'] = $data['level']+1;
if(empty($data['name'])){
$this->error("请填写地区名称", $referurl);
}else{
$res = M('region')->where("parent_id = ".$data['parent_id']." and name='".$data['name']."'")->find();
if(empty($res)){
M('region')->add($data);
$this->success("操作成功", $referurl);
}else{
$this->error("该区域下已有该地区,请不要重复添加", $referurl);
}
}
}else{
M('region')->where("id=$id or parent_id=$id")->delete();
$this->success("操作成功", $referurl);
}
}
}