"; //追加头文件内容 private $tar_ext = '.zip'; //下载扩展名 private $backdir; //备份目录 private $prefilename = 'multibak_'; /** * __construct * @return mixed 返回值 */ public function __construct() { $this->backdir = DATA_DIR.'/backup'; } /** * 获取 * @param mixed $var var * @return mixed 返回结果 */ public function get($var='') { if(!$var) return false; return $this->$var; } /** * 获取List * @return mixed 返回结果 */ public function getList(){ $dir = $this->backdir; if(!is_dir($dir))return false; $handle=opendir($dir); if ($handle = opendir($dir)) { $return = array(); while (false !== ($file = readdir($handle))) { if($file[0]=='.') continue; if( is_file($dir.'/'.$file) ){ //备份时间取文件名字 $array = explode( '.',$file ); $temp = array(); if( count($array)==3 ) { $temp['app'] = $array[0]; $nfilename = $array[1]; } else { $nfilename = $array[0]; $temp['app'] = '全局备份'; } $datetime = ltrim($nfilename,$this->prefilename); if( strlen($datetime)!=14 ) continue; $datetime = mktime( substr($datetime,8,2) , substr($datetime,10,2) , substr($datetime,12,2) , substr($datetime,4,2) , substr($datetime,6,2) , substr($datetime,0,4) ); $temp['name'] = str_replace('.php', $this->tar_ext, $file); $temp['size'] = filesize($dir .'/'. $file); $temp['time'] = $datetime; if( end($array)==trim($this->tar_ext,'.') ) { $this->convertFile( $dir,$file ); @unlink($dir.'/'.$file); } $return[] = $temp; } } krsort($return); closedir($handle); } return $return; } /** * uninstall_backup * @param mixed $app app * @return mixed 返回值 */ public function uninstall_backup( $app ) { $oMysqlDump = kernel::single("desktop_system_mysqldumper"); $backdir = $this->backdir; $dirname = date("Ymdhis"); is_dir($backdir) or mkdir($backdir, 0755, true); $oMysqlDump->multi_dump_sdf( $app,$backdir .'/' . $dirname ); $this->create_tar( $backdir,$dirname,$app ); } /** * start_backup_sdf * @param mixed $params 参数 * @param mixed $nexturl nexturl * @return mixed 返回值 */ public function start_backup_sdf(&$params,&$nexturl){ set_time_limit(0); header("Content-type:text/html;charset=utf-8"); $app = $params['appname']; $dirname = $params['dirname']; #$cols = $params['cols']; #$model = $params['model']; #$startid = $params['startid']; $oMysqlDump = kernel::single("desktop_system_mysqldumper"); $backdir = $this->backdir; $oMysqlDump->tableid = $tableid; $oMysqlDump->startid = $startid; is_dir($backdir) or mkdir($backdir, 0755, true); is_dir($backdir .'/' . $dirname) or mkdir($backdir .'/' . $dirname, 0755, true); $app = $oMysqlDump->multi_dump_sdf( $app,$backdir .'/' . $dirname ); if($app){ $nexturl = "index.php?app=desktop&ctl=backup&act=backup_sdf&appname=$app&dirname=$dirname"; $params['app'] = $app; } else { return $this->create_tar( $backdir,$dirname ); } return false; } /** * 生成tar包 */ private function create_tar( $backdir,$dirname,$app='' ) { $tar = kernel::single("base_tar"); $dir = $backdir. '/' . $dirname; chdir($dir); $size = $this->add_tar( $dir,$tar ); $size = ceil($size/1024/1024) + 128; ini_set("memory_limit", "{$size}M"); $tar->filename = ($app?$app.'.':''). $this->prefilename.$dirname.$this->tar_ext; $tar->saveTar(); @copy($dir . '/' . $tar->filename, $backdir.'/'.$tar->filename); $this->convertFile($backdir, $tar->filename, '.php'); if(is_resource($tar->tar_file)) { fclose($tar->tar_file); } @unlink($tar->filename); @unlink($backdir.'/'.$tar->filename); $dir = $backdir. '/' . $dirname; chdir($dir); if ($handle = opendir($dir)) { while (false !== ($file = readdir($handle))) { if(is_file($file)) { @unlink($file); } } closedir($handle); } utils::remove_p($dir); return true; } private function add_tar( $dir,&$tar,$parentdir='' ) { $size = 0; if ($handle = opendir($dir)) { while (false !== ($file = readdir($handle))) { if($file[0]!='.') { if( is_file($dir.'/'.$file) ) { $size += filesize($parentdir.$file); $tar->addFile($parentdir.$file); } else { $tar->addDirectory($parentdir.$file); $size += $this->add_tar( $dir.'/'.$file, $tar, $parentdir.$file.'/' ); } } } closedir($handle); } return $size; } /** * download * @param mixed $file file * @return mixed 返回值 */ public function download($file) { $dir = DATA_DIR.'/backup/'; $file = str_replace($this->tar_ext, '.php', $file); if(!file_exists($dir . $file)){ return false; } $etag = md5_file($dir . $file); header('Etag: '.$etag); if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag){ header('HTTP/1.1 304 Not Modified',true,304); exit(0); }else{ set_time_limit(0); ob_end_clean(); $content_size = filesize($dir . $file) - strlen($this->header); $filename = substr($file, 0, strrpos($file, '.')) . $this->tar_ext; header("Content-Disposition: attachment; filename=\"$filename\""); header("Content-Length: " . $content_size); $handle = fopen($dir . $file, "r"); $flag = false; while($buffer = fread($handle,102400)){ if(!$flag) $buffer = str_replace($this->header, '', $buffer); echo $buffer; $flag = true; flush(); } fclose($handle); } } function recover($sTgz,&$vols,$fileid,&$pre_app){ $prefix = substr($sTgz,0,23); $sTmpDir = DATA_DIR.'/tmp/'.md5($sTgz).'/'; $sTgz = str_replace($this->tar_ext, '.php', $sTgz); if($fileid==1){ $vols = 0; $rTar = kernel::single("base_tar"); is_dir($sTmpDir) or mkdir($sTmpDir, 0755, true); $file = DATA_DIR.'/backup/'.$sTgz; $size = filesize($file); $size = ceil($size/1024/1024) + 128; ini_set("memory_limit", "{$size}M"); $newFile = $this->convertFile(DATA_DIR.'/backup/', $sTgz, $this->tar_ext); if($rTar->openTAR($newFile, null)){ if(!$rTar->files) return false; foreach($rTar->files as $id => $aFile) { if( substr($aFile['name'],0,4)=='sdf/') $vols++; $sPath=$sTmpDir.$aFile['name']; is_dir( dirname($sPath) ) or mkdir( dirname($sPath),0755,true ); file_put_contents($sPath,$rTar->getContents($aFile)); chmod($sPath,0755); } } $rTar->closeTAR(); @unlink($newFile); return $this->comeback($sTmpDir, 1, $vols, $pre_app); }else{ return $this->comeback($sTmpDir, $fileid, $vols, $pre_app); } } function comeback($sDir, $fileid=1, $vols, &$pre_app){ $dir = $sDir; $sDir = $sDir .'/sdf'; if(!is_dir($sDir)) return false; chdir($sDir); if($rHandle=opendir($sDir)){ while(false!==($sFile=readdir($rHandle))){ if($sFile[0]=='.')continue; $handle = fopen($sFile,'r'); $app = substr($sFile, 0, strpos($sFile, '.')); $model = substr($sFile, strpos($sFile, '.')+1, -(strpos(strrev($sFile), '.') + 1)); $model = strpos($model, '.') ? substr($model, 0, strpos($model, '.')) : $model; if(!$app || !$model) return false; if( app::get($app)->is_actived() ) { //APP安装了继续跑 $o = app::get($app)->model($model); $this->app_update( $dir,$app,$pre_app,$model,$o ); $str = null; while($sdf=$this->fgetline($handle)){ if(!is_array(@unserialize($sdf))){ $buffer .= $sdf; $sdf = @unserialize($buffer); if(!is_array($sdf)) continue; }else{ $sdf = @unserialize($sdf); } if( $app=='base' && $model=='app_content' ) { if( !$sdf['app_id'] ) continue; if( !isset($arr_app_status[$sdf['app_id']]) ) $arr_app_status[$sdf['app_id']] = app::get($sdf['app_id'])->is_actived(); if( !$arr_app_status[$sdf['app_id']] ) continue; } //删除kvstore主键 避免冲突 session if( $app=='base' && $model=='kvstore' ) unset( $sdf['id'] ); $return = @$o->insert($sdf); $buffer = null; } } else { $this->show_message .= 'app: '.$app .' 没有安装!数据无法还原!
'; } fclose($handle); @unlink($sFile); $pre_app = $app; break; } closedir($rHandle); if( !$sFile ) { $this->app_update( $dir,$app,$pre_app ); utils::remove_p($sDir); } if( $fileid==$vols ) { $this->post_comeback($dir); utils::remove_p($dir); } } } ////////////////////////////////////////////////////////////////////////// //数据还原之后 /////////////////////////////////////////////////////////////////////////// private function post_comeback($dir) { if($rHandle=opendir($dir.'/dbschema/')){ while(false!==($app=readdir($rHandle))){ if( $app[0]=='.' ) continue; if( !is_dir($dir.'/dbschema/'.$app) ) continue; #if( $handle=opendir($dir.'/dbschema/'.$app) ) { # while(false!==($sFile=readdir($handle))){ # if( $sFile[0]=='.' ) continue; # $tmp_model = substr($sFile,0,strpos($sFile,'.')); //最后会修复表结构到最新 以下没有意义 #$dbschema_file = $dir.'/dbschema/'.$app.'/'.$sFile; #if( $db[$tmp_model]['unbackup'] ) continue; #$this->create_table( $pre_app,$tmp_model,$o,$dbschema_file ); # } #} if( !$this->dbtable ) $this->dbtable = kernel::single('base_application_dbtable'); $this->dbtable->update($app); } } } private function app_update( $dir,$app,$pre_app,$model='',$o='' ) { if( !$app ) return false; $dbschema_file = $dir.'/dbschema/'.$app.'/'.$model.'.php'; $dbschema_file_bak = $dir.'/dbschema/'.$app.'/'.$model.'.bak.php';; if( is_file($dbschema_file) ) { $this->create_table( $app,$model,$o,$dbschema_file ); #unlink( $dbschema_file ); rename($dbschema_file,$dbschema_file_bak); } else if(is_file($dbschema_file_bak)) { $this->create_table( $app,$model,$o,$dbschema_file_bak,false ); } } /* * 创建数据表 */ private function create_table( $app,$model,$o,$dbschema_file,$createtable=true ) { if( !$app ) return false; if( !$model ) return false; require( $dbschema_file ); if( !$this->dbtable ) $this->dbtable = kernel::single('base_application_dbtable'); $this->dbtable->target_app = app::get($app); //是否默认使用innodb $this->dbtable->_enable_innodb = 'YES'; $this->dbtable->key = $model; $real_table_name = $this->dbtable->real_table_name(); $define = $db[$model]; $this->get_defined_dbsdf( $define ); $this->dbtable->_define[$real_table_name] = $define; if( $createtable ) { $sql = $this->dbtable->get_sql("sdb_{$app}_{$model}"); $o->db->exec("DROP TABLE IF EXISTS sdb_{$app}_{$model}"); $o->db->exec($sql); } else { } } private function get_defined_dbsdf( &$define ) { foreach($define['columns'] as $k=>$v){ if($v['pkey']) $define['idColumn'][$k] = $k; if($v['is_title']) $define['textColumn'][$k] = $k; if($v['in_list']){ $define['in_list'][] = $k; if($v['default_in_list']){ $define['default_in_list'][] = $k; } } $define['columns'][$k] = $this->dbtable->_prepare_column($k, $v); if(isset($v['pkey']) && $v['pkey']){ $define['pkeys'][$k] = $k; } } if(!$define['idColumn']){ $define['idColumn'] = key($define['columns']); }elseif(count($define['idColumn'])==1){ $define['idColumn'] = current($define['idColumn']); } if(!$define['textColumn']){ $keys = array_keys($define['columns']); $define['textColumn'] = $keys[1]; }elseif(count($define['idColumn'])==1){ $define['textColumn'] = current($define['textColumn']); } } /** * 文件类型转换 */ private function convertFile($dir, $file, $type='.php') { $dir = rtrim($dir, '/') . '/'; $new_file_name = substr($file, 0, -(strpos(strrev($file), '.')+1)) . $type; $newFile = $dir . $new_file_name; $flag = true; if($type==$this->tar_ext) { //还原时从php转换成tar包 $flag = false; //is_dir($dir .'/tmptar/') or mkdir($dir .'/tmptar/'); //$newFile = $dir .'/tmptar/'. md5($newFile); if(file_exists($newFile)) { //如果是tar文件转换成php形式 $this->convertFile( $dir,$new_file_name ); } } if(file_exists($newFile)) { return $newFile; } $handle = fopen($newFile, 'x'); if($flag) { fwrite($handle, $this->header); } $src = fopen($dir . $file, 'r'); while (!feof($src)) { $contents = fgets($src); if(!$flag && strpos($contents, $this->header)!==false) $contents = substr($contents, strlen($this->header)); if($contents) { fwrite($handle, $contents); } $flag = true; } fclose($src); fclose($handle); return $newFile; } function fgetline($handle){ $buffer = fgets($handle, 4096); if (!$buffer){ return false; } if(( 4095 > strlen($buffer)) || ( 4095 == strlen($buffer) && "\n" == $buffer[4094] )){ $line = $buffer; }else{ $line = $buffer; while( 4095 == strlen($buffer) && "\n" != $buffer[4094] ){ $buffer = fgets($handle,4096); $line.=$buffer; } } return $line; } function removeTgz($sFile){ #foreach($aTgz as $sFile){ $pathinfo = pathinfo($sFile); @unlink(DATA_DIR.'/backup/'.$pathinfo['filename'].'.php'); #} return true; } function __finish($sDir){ $this->__removeDir($sDir); return $sDir; } function __removeDir($sDir){ if($rHandle=opendir($sDir)){ while(false!==($sItem=readdir($rHandle))){ if ($sItem!='.' && $sItem!='..'){ if(is_dir($sDir.'/'.$sItem)){ $this->__removeDir($sDir.'/'.$sItem); }else{ @unlink($sDir.'/'.$sItem); } } } closedir($rHandle); utils::remove_p($sDir); } } //*/ }