// +---------------------------------------------------------------------- namespace Admin\Controller; use Think\Db; use OT\Database; /** * 数据库备份还原控制器 * @author 麦当苗儿 */ class DatabaseController extends AdminController{ public function __construct(){ parent::__construct(); $this->db=Db::getInstance(); $this->path="./Application/Data/sqlBake/" ;//备份路径 $this->filesize=100;//KB 文件备份大小 $this->max_num=300;//条 单个文件记录数最多不能超过的条数【防止有的数据较小,都上千条数据了文件大小还没有超过filesize】 ini_set ('memory_limit', '1024M');//这里是将php.ini的内存大小临时修改为比较大的,因为数据备份需要占用比较大的内存 } //数据库列表 public function index(){ $Db = Db::getInstance(); $list = $Db->query('SHOW TABLE STATUS'); $list = array_map('array_change_key_case', $list); $this->pagetitle = '数据备份'; $this->assign('data', $list); $this->display($type); } //数据库备份列表 public function recovery(){ $path = realpath($this->path); $flag = \FilesystemIterator::KEY_AS_FILENAME; $glob = new \FilesystemIterator($path, $flag); $list = array(); $i=0; foreach ($glob as $name => $file) { $list[$i]["name"]=$name; $list[$i]["size"]=0; $list[$i]["file_num"]=0; //获取文件数量和大小 $path2 = realpath($this->path."/".$name."/config.json"); $text=$this->ReadFiletext($path2); $config= json_decode($text); $list[$i]["file_num"]=$config->file_num; $list[$i]["file_size"]=$config->file_size; // $i++; } $list=array_reverse($list);//倒叙 $this->assign('data', $list); $this->pagetitle = '恢复数据'; $this->display(); } //获取文件大小 /* //添加大量备份数据,用于测试的 public function inserts(){ $Model = M(); $sql='insert into db_page(name,pagemod,template_id,pagetitle,pagetext)value("测试标题",1,85,"测试标题","<div class="quan suhz kangma product_jy" id="kangma_gene"><div class="suhz_nei"><img src="skin/images/bg43.jpg"/></div></div><div class="quan product_tab"><div class="product_tab_nei"><table class="tab_nei_body" cellpadding="0" cellspacing="0"><tbody><tr class="firstRow"><td></td><td>全基因组测序</td><td>全外显子测序</td><td>基因芯片</td><td>单基因测序</td><td>单位点检测</td></tr><tr><td>检测内容</td><td>测序全基因组</td><td>测序外显子组</td><td>检测基因组多个位点</td><td>测序单个基因</td><td>检测基因组单个位点</td></tr><tr><td>基因组覆盖度</td><td>100%</td><td>~1.5%</td><td>&lt;0.01%</td><td>&lt;0.001%</td><td>&lt;0.001%</td></tr><tr><td>精准度</td><td>最高</td><td>中等</td><td>低</td><td>低</td><td>低</td></tr><tr><td>单个突变位点的费用</td><td>最低</td><td>中等</td><td>中等</td><td>高</td><td>高</td></tr><tr><td>终身受益程度</td><td>一次检测终身受益</td><td>需多次检测</td><td>需多次检测</td><td>需多次检测</td><td>需多次检测</td></tr></tbody></table></div><div style="font-size:22px; font-weight:bolder; color:#f28a27; margin-top:20px; text-align:center">选择全基因组检测,是每个人一生必须做的!(避免盲人摸象,精确了解您的疾病内因风险!)</div></div><div class="quan product_pg"><div class="product_pg_nei"><div class="pg_nei_img"><img src="skin/images/bg45.jpg"/></div><div class="pg_nei_wen"><div class="nei_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bg46.jpg"/></div><div class="wen_xun_text"><dl><dd><span>更完整的数据</span></dd><dt><p>检测人体所有<em>25000个</em>基因,</p><p><em>30亿</em>碱基对,</p><p><em>90G</em>原始数据量,</p><p>全基因组检测才完整。</p></dt></dl></div></div><div class="nei_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bg47.jpg"/></div><div class="wen_xun_text"><dl><dd><span>更精准的评估</span></dd><dt><p>采用以基因组区块为单位的风险评估模型,经过了全球唯一的全基因组信息和完整医学记录的大数据平台验证。</p></dt></dl></div></div><div class="nei_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bg48.jpg"/></div><div class="wen_xun_text"><dl><dd><span>更权威的解读</span></dd><dt><p>ABMGG认证的国际权威专家最终审核基因报告,并由具有丰富临床经验的遗传学、医学、营养学专家团队提供解读服务。</p></dt></dl></div></div><div class="nei_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bg49.jpg"/></div><div class="wen_xun_text"><dl><dd><span>更持续的延展</span></dd><dt><p>个人基因数据全掌握,利用前沿基因研究成果与疾病关联每周更新实时风险提示。一生一次检测,终生解读升级。</p></dt></dl></div></div><div class="nei_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bg50.jpg"/></div><div class="wen_xun_text"><dl><dd><span>更健全的资质</span></dd><dt><p>拥有中国首家获得美国CAP、CLIA以及加州认证的测序实验室。</p></dt></dl></div></div><div class="clear"></div></div><div class="pg_nei_last" id="meig"><div class="nei_last_title"><p><span>康码全基因组检测疾病风险评估</span></p><p><span>由美国ABMGG专家领导的医学、遗传学专家团队</span>为您提供涵盖<span><strong>肿瘤、</strong></span></p><p><span><strong>心脑血管疾病、代谢性疾病、免疫相关性疾病、家族性的隐性携带者状态</strong></span>等全面疾病风险评估。</p></div><div class="nei_last_wen jz"><div class="last_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bn70.png" class="flip"/></div><div class="wen_xun_text"><dl><dd>1ml</dd><dt><p>无创唾液样本采集</p></dt></dl></div></div><div class="last_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bn71.png" class="flip"/></div><div class="wen_xun_text"><dl><dd>25000个基因</dd><dt><p>检测全部DNA</p></dt></dl></div></div><div class="last_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bn72.png" class="flip"/></div><div class="wen_xun_text"><dl><dd>457+</dd><dt><p>种疾病先天风险评估</p></dt></dl></div></div><div class="clear"></div></div></div></div></div><div class="quan product_pg"><div class="product_pg_nei"><div class="pg_nei_img"><img src="skin/images/bg51.jpg"/></div><div class="product_benefit"><div class="product_benefit_title"><span>您能得到</span>Benefit</div><div class="product_benefit_wen"><div class="benefit_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bn73.png"/></div><div class="wen_xun_text"><dl><dd><p>生命之书</p><p>您的个人基因图谱</p></dd><dt>根据测序分析结果定制纸质版基因报告,全面揭示457种疾病先天风险</dt></dl></div></div><div class="benefit_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bn74.png"/></div><div class="wen_xun_text"><dl><dd><p>电子基因报告</p><p>您的掌上基因名片</p></dd><dt>康码APP将同步呈现您的电子基因报告,随时随地查阅</dt></dl></div></div><div class="benefit_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bn75.png"/></div><div class="wen_xun_text"><dl><dd><p>专家解读</p><p>您的私人健康顾问</p></dd><dt>由康码遗传、营养、医学专家为您专业解读《生命之书》,并为您定制个性化健康管理方案</dt></dl></div></div><div class="benefit_wen_xun fl"><div class="wen_xun_img"><img src="skin/images/bn76.png"/></div><div class="wen_xun_text"><dl><dd><p>隐私保护</p><p>您的健康隐私保护专家</p></dd><dt>康码严格遵循多项权威认证: ISO 27001认证HIPAA法案(美国医疗健康产业通用标准)、CLIA、GCP、欧盟法规等多种规则</dt></dl></div></div><div class="clear"></div></div></div></div></div><div class="quan product_case"><div class="product_case_nei shadow6"><div class="product_case_img"><img src="skin/images/bg52.jpg"/></div><div class="product_case_wen"><div class="case_wen_xun" id="case_1"><div class="case_wen_left fl"><img src="/d/image/20180416/5ad4870b7de29.png" _src="/d/image/20180416/5ad4870b7de29.png" width="406" height="460" border="0" vspace="0" title="" alt="" style="width: 406px; height: 460px;"/></div><div class="case_wen_right fr" id="scroll-1"><dl><dd>客户案例</dd><p>在做康码全基因组检测之前,S女士对“林奇综合征”是完全陌生的。而在S女士的《生命之书》报告中,“林奇综合征”项目被检测出阳性。这意味着什么?S女士体内有一个DNA错配修复基因(MMR)存在突变,意味着她比一般人更容易罹患大肠癌、子宫内膜癌或者其他癌症....</p><a href="/index.php?m=Home&c=View&a=index&catid=8&id=1">查看详情<em class="fa fa-angle-right"></em></a></dl></div><div class="clear"></div></div><div class="case_wen_xun" id="case_2"><div class="case_wen_left fl"><img src="/d/image/20180416/5ad487268583b.png" _src="/d/image/20180416/5ad487268583b.png" width="406" height="460" border="0" vspace="0" title="" alt="" style="width: 406px; height: 460px;"/></div><div class="case_wen_right fr" id="scroll-1"><dl><dd>客户案例</dd><p>经过CT检查后,M先生被诊断为肾结石,医生怀疑为草酸钙结石。基因检测报告(402种携带者状态)显示其SLC3A1基因呈阳性(胱氨酸尿症),结果指向了——胱氨酸结石....</p><a href="/index.php?m=Home&c=View&a=index&catid=9&id=2">查看详情<em class="fa fa-angle-right"></em></a></dl></div><div class="clear"></div></div><div class="case_wen_xun" id="case_3"><div class="case_wen_left fl"><img src="/d/image/20180416/5ad4875c31975.png" _src="/d/image/20180416/5ad4875c31975.png" width="406" height="460" border="0" vspace="0" title="" alt="" style="width: 406px; height: 460px;"/></div><div class="case_wen_right fr" id="scroll-1"><dl><dd>客户案例</dd><p>在没有为人父母之前,我们对孩子及他的未来可能有各种各样的期待和设想。但真的有了孩子,才知道自己的最大期待就是他们健康平安。</p><p>我相信每对父母都会为此甘愿付出一切,我们在孩子成长的过程中小心翼翼、如履薄冰。所以,当我第一次知道因为自己的遗传基因可能让儿子患上疾病时,真的非常恐慌....</p><a href="/index.php?m=Home&c=View&a=index&catid=9&id=3">查看详情<em class="fa fa-angle-right"></em></a></dl></div><div class="clear"></div></div></div></div></div><div class="quan product_lx"><div class="product_lx_nei"><div class="lx_nei_title"><div class="fl nei_title_left">康码-<span>铂金版</span></div><div class="fr nei_title_right">康码-<span>炫银版</span></div><div class="clear"></div></div><div class="lx_nei_wen"><div class="nei_wen_xun fl"><dl><dd><span>全基因组检测及报告解读 &nbsp;</span></dd><dt><p>全基因组检测</p><p>457项疾病先天风险评估报告《生命之书》</p><p>基因新发现(2年)</p><p>定制新药报告和专家解读(2次)</p><p>博士级专家报告解读服务</p></dt></dl></div><div class="nei_wen_xun fl"><dl><dd><span>2年康码会员服务</span></dd><dt><p>个性化健康管理方案(定制体检方案、专属营养方案、APP智能健康资讯)海外体检预约服务</p><p>海外体检预约服务</p><p>海外转诊咨询服务</p><p>全球名医推荐服务</p></dt></dl></div><div class="nei_wen_xun fl"><dl><dd><span>全基因组检测及报告解读</span></dd><dt><p>全基因组检测</p><p>457项疾病先天风险评估报告《生命之书》</p><p>基因新发现(2年)</p><p>定制新药报告和专家解读(2次)</p><p>博士级专家报告解读服务</p></dt></dl></div><div class="clear"></div></div><div class="lx_nei_img"><img src="skin/images/bn78.png"/></div></div></div>");'; for($i=1;$i<=10000;$i++){ $Model->execute($sql); } }*/ //字段列表 public function show_field($table=NULL){ $Db = Db::getInstance(); $list = $Db->query("SHOW FIELDS FROM `".$table."`"); $this->pagetitle = $table; $this->assign('data', $list); $this->display($type); } /** * 优化表 * @param String $tables 表名 * @author 麦当苗儿 */ public function optimize($tables = null){ if($tables) { $Db = Db::getInstance(); if(is_array($tables)){ $tables = implode('`,`', $tables); $list = $Db->query("OPTIMIZE TABLE `{$tables}`"); if($list){ $this->success("数据表优化完成!"); } else { $this->error("数据表优化出错请重试!"); } } else { $list = $Db->query("OPTIMIZE TABLE `{$tables}`"); if($list){ $this->success("数据表'{$tables}'优化完成!"); } else { $this->error("数据表'{$tables}'优化出错请重试!"); } } } else { $this->error("请指定要优化的表!"); } } /** * 修复表 * @param String $tables 表名 * @author 麦当苗儿 */ public function repair($tables = null){ if($tables) { $Db = Db::getInstance(); if(is_array($tables)){ $tables = implode('`,`', $tables); $list = $Db->query("REPAIR TABLE `{$tables}`"); if($list){ $this->success("数据表修复完成!"); } else { $this->error("数据表修复出错请重试!"); } } else { $list = $Db->query("REPAIR TABLE `{$tables}`"); if($list){ $this->success("数据表'{$tables}'修复完成!"); } else { $this->error("数据表'{$tables}'修复出错请重试!"); } } } else { $this->error("请指定要修复的表!"); } } //删除备份目录 public function delete($name){ if(!$name){ $this->error("参数错误"); } $dir =$this->path."/".$name."/"; $this->del_dir($dir); D("UserLog")->add("delete","DatabaseBake"); $this->success("删除成功!"); } //删除目录 protected function del_dir($dir){ $dh=opendir($dir); while ($file=readdir($dh)) { if($file!="." && $file!="..") { $fullpath=$dir."/".$file; if(!is_dir($fullpath)) { @unlink($fullpath); } else { $this->del_dir($fullpath); } } } closedir($dh); if(rmdir($dir)){ return true; } else { return false; } } //初使化备份 function Start_DoBak(){ $add=$_POST; $tablename=$add['tables']; $count=count($tablename); if(empty($count)) { $this->error("请选择要备份的数据表"); } $bakpath=$this->path.C("DB_NAME")."_".date("YmdHis")."/"; $this->DoMkdir($bakpath); session("bakpath",$bakpath);//备份的文件路径 //生成说明文件 $readme=$add['readme']; $rfile=$bakpath."readme.txt"; $readme.="\r\n\r\nBaktime: ".date("Y-m-d H:i:s"); $this->WriteFiletext_n($rfile,$readme); //生成配置文件 for($i=0;$i<$count;$i++){ $d_table[$tablename[$i]]=0; } $string=array( "tables"=>$tablename, "table_files"=>$d_table, ); $string= json_encode($string); $cfile=$bakpath."config.json"; $this->WriteFiletext_n($cfile,$string); $this->success($tablename); } //执行备份(按文件大小) public function Ebak_BakExe(){ $path=session("bakpath");//备份路径 $table_index=I("get.table_index",0,"intval");//当前备份的表对应数据下标 //当前config.json文件配置信息 $config=$this->ReadFiletext($path."config.json"); $config=json_decode($config); // $talbe_name=$config->tables[$table_index]; if(!$talbe_name){ $return["progress"]=100; $return["bake_end"]=1; $this->UpdateConfig($path); D("UserLog")->add("add","DatabaseBake"); $this->success($return);exit; } //注意,前台js根据bake_end=1来判断是否结束 $return["bake_end"]=0; // $s=I("get.start",0,"intval");//开始记录数 $p=I("get.p",0,"intval");//文件后缀 //记录条数 $status_r=$this->GetTotal($talbe_name); $num=$status_r['rows']; //备份数据库结构 if(!$s){ $dumpsql.=$this->Ebak_Returnstru($talbe_name,$b_strufour); } //取得数据 $data=$this->db->query("select * from `".$talbe_name."` limit $s,$num"); //取得字段数 $field_arr=$this->db->query("SHOW FIELDS FROM `".$talbe_name."`"); $b=0; $now_s=0;//这个主要用来防止有的数据表字段和数据过小,可能会出现条数已经1000条以上了文件大小还没有超过100KB,这样会造成恢复数据的时候浏览器卡死状态 foreach($data as $r){ $b=1; $now_s++; $s++; $dumpsql.="\$this->E_D(\"replace into `".$talbe_name."` values("; $first=1; foreach($field_arr as $field){ //首字段 if(empty($first)){ $dumpsql.=','; }else{ $first=0; } $myi=$i+1; if($r[$field[field]]===NULL){ $dumpsql.='NULL'; }else{ $dumpsql.=$this->Ebak_ReSqlFtext($r[$field[field]]); } } $dumpsql.=");\");\r\n"; //是否超过限制 if(strlen($dumpsql)>=$this->filesize*1024||$now_s>$this->max_num){//当文件超过指定大小,或者当前已经循环条数大于500的时候则进入下一个备份 $p++; $sfile=$path."/".$talbe_name."_".$p.".php"; $dumpsql=""; $this->WriteFiletext_n($sfile,$dumpsql); //进入下一个文件备份 $return["progress"]=$this->progress_Bar($config,$table_index,$num,$s); $return["start"]=$s; $return["p"]=$p; $return["table_index"]=$table_index; $this->success($return); exit; } } //最后一个备份 if(empty($p)||$b==1) { $p++; $sfile=$path."/".$talbe_name."_".$p.".php"; $dumpsql=""; $this->WriteFiletext_n($sfile,$dumpsql); } $this->Ebak_RepFilenum($p,$talbe_name,$path); //进入下一个表 $return["progress"]=$this->progress_Bar($config,$table_index,$num,$s); $table_index++; $return["start"]=0; $return["p"]=0; $return["table_index"]=$table_index; $this->success($return); } //返回备份进度条 protected function progress_Bar($config,$table_index,$total,$start){ //当前所占第几个表 $self=($table_index)/count($config->tables)*100; $self1=($start/$total)*(1/count($config->tables))*100; $progress=sprintf("%.2f",($self+$self1)); return $progress; } //字符过虑(addslashes) function escape_addsstr($str){ $str=addslashes($str); $str=str_replace('\\\'','\'\'',$str); $str=str_replace("\\\\","\\\\\\\\",$str); $str=str_replace('$','\$',$str); return $str; } //字符过虑(db) protected function escape_dbstr($str){ $str=mysql_real_escape_string($str); $str=str_replace('\\\'','\'\'',$str); $str=str_replace("\\\\","\\\\\\\\",$str); $str=str_replace('$','\$',$str); return $str; } //字符过虑 function escape_str($str){ global $ebak_set_escapetype; if($ebak_set_escapetype==2)//real_escape_string { $str=$this->escape_dbstr($str); } else//addslashes { $str=$this->escape_addsstr($str); } return $str; } //返回字段内容 protected function Ebak_ReSqlFtext($str){ $restr='\''.$this->escape_str($str).'\''; return $restr; } //查询记录数 protected function GetTotal($tbname){ $total=$this->db->query("select count(*)as rows from ".$tbname.";"); //$tr=$this->db->query("SHOW TABLE STATUS LIKE '".$tbname."';");//SHOW TABLE STATUS的数量有时候是不准确的,所以这里切记不要使用 return $total[0]; } //返回数据库结构 protected function Ebak_Returnstru($table,$strufour){ global $empire; $dumpsql.="\$this->E_D(\"DROP TABLE IF EXISTS `".$table."`;\");\r\n"; //设置引号 $usql=$this->db->execute("SET SQL_QUOTE_SHOW_CREATE=1;"); //数据表结构 $arr=$this->db->query("SHOW CREATE TABLE `$table`;"); $create=str_replace("\"","\\\"",$arr[0]["create table"]); $dumpsql.="\$this->E_C(\"".$create."\");\r\n"; return $dumpsql; } //替换文件数 protected function Ebak_RepFilenum($p,$table,$path){ if(empty($p)){$p=0;} $file=$path."/config.json"; $text=$this->ReadFiletext($file); $rep1="\"".$table."\":0"; $rep2="\"".$table."\":".$p; $text=str_replace($rep1,$rep2,$text); $this->WriteFiletext_n($file,$text); } //更新config文件信息 protected function UpdateConfig($path){ if(empty($p)){$p=0;} $con_file=$path."/config.json"; $text=$this->ReadFiletext($con_file); $config= json_decode($text); // $config->file_size=0; $config->file_num=0; //获取文件数量和大小 $path = realpath($path); $flag = \FilesystemIterator::KEY_AS_FILENAME; $glob = new \FilesystemIterator($path,$flag); foreach ($glob as $name => $file) { $size=$file->getSize(); $config->file_size=$config->file_size+$size; $config->file_num++; } //写入文件 $file=$path."/config.json"; $text= json_encode($config); $this->WriteFiletext_n($file,$text); } //取得文件内容 protected function ReadFiletext($filepath){ $htmlfp=@fopen($filepath,"r"); while($data=@fread($htmlfp,1000)) { $string.=$data; } @fclose($htmlfp); return $string; } //写文件 protected function WriteFiletext_n($filepath,$string){ $fp=@fopen($filepath,"w"); @fputs($fp,$string); @fclose($fp); if(empty($filechmod)) { @chmod($filepath,0777); } } //建立目录函数 protected function DoMkdir($path){ //不存在则建立 if(!file_exists($path)) { $mk=@mkdir($path,0777); @chmod($path,0777); if(empty($mk)) { $this->error("创建目录失败"); } } return true; } /** * 还原数据库 * @author 麦当苗儿 */ public function import(){ $name=I("get.name"); if(!$name){ $this->error("缺少参数"); } $path=$this->path.$name; $table_index=I("get.table_index",0,"intval"); $p=I("get.p",1,"intval"); // $con_file=$path."/config.json"; $text=$this->ReadFiletext($con_file); if(!$text){ $this->error("目录文件不存在,或者文件缺少"); } $config= json_decode($text); //如果没有表了,正明恢复成功了 if(!$config->tables[$table_index]){ $this->success("ok");exit; } //循环的当前表名 $this_table=$config->tables[$table_index]; //开始恢复数据 $file=$path."/".$this_table."_".$p.".php"; include_once($file); //进度条 $return["progress"]=$this->import_progress_Bar($config,$table_index,$config->table_files->$this_table,$p); if($return["progress"]==100){ D("UserLog")->add("update","DatabaseBake"); } $return["name"]=$name; //如果文件卷标数等于最大的,则进入下一个表 if($p==$config->table_files->$this_table){ $return["table_index"]=$table_index+1; $return["p"]=1; }else{ $return["table_index"]=$table_index; $return["p"]=$p+1; } $this->success($return);exit; } //返回恢复数据的进度条 protected function import_progress_Bar($config,$table_index,$total_p,$p){ //当前所占第几个表 $self=($table_index)/count($config->tables)*100; $self1=($p/$total_p)*(1/count($config->tables))*100; $progress=sprintf("%.2f",($self+$self1)); return $progress; } //执行SQL protected function E_D($sql){ $this->db->execute($sql); } //建立表 protected function E_C($sql){ //替换数据表引擎(因为有的服务器不支持InnoDB有的不支持MyISAM 这里主要是获取当前的默认引擎是什么,然后创建表的时候按这个引擎来创建) $sql=preg_replace("/(?i)ENGINE=([a-zA-Z])+ /", "ENGINE=".$this->get_engine()." ", $sql); $this->db->execute($sql); } //获取数据库存储类型 protected function get_engine(){ $result=$this->db->query("show variables like '%storage_engine%'"); return $result[0][value]; } }