$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(); } 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(); } /** * 读取要导入的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(); } 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); } } }