sys_version_num = Db::name('system')->where('id',1)->value('sys_version_num'); } /** 升级界面 */ public function index() { $sys_version_num = Db::name('system')->field('sys_version_num,key,upcheck_url,upgrade_url')->find(1); View::assign('ver_num',$sys_version_num); return View::fetch(); } //设置key public function key() { $data = Request::param(); if($data['key']== ''){ return json(['code'=>0,'msg'=>'请填写正确的key']); } $res = Db::name('system')->update(['key'=>$data['key'],'id'=>1]); if($res){ $res = ['code'=>1,'msg'=>'保存成功']; } else { $res = ['code'=>0,'msg'=>'保存失败']; } return json($res); } //修改key public function keyedit() { $key = Db::name('system')->field('key,upcheck_url,upgrade_url')->find(1); if(Request::isAjax()){ $data = Request::param(); if($data['key']== ''){ return json(['code'=>0,'msg'=>'请正确填写申请到的key']); } $res = Db::name('system')->update(['key'=>$data['key'],'upcheck_url'=>$data['upcheck_url'],'upgrade_url'=>$data['upgrade_url'],'id'=>1]); if($res){ $res = ['code'=>1,'msg'=>'修改成功']; } else { $res = ['code'=>0,'msg'=>'修改失败']; } return json($res); } View::assign('key',$key); return View::fetch(); } //升级前的版本检测 public function check($url) { $url = $url.'?ver='.$this->sys_version_num; $ch =curl_init (); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch,CURLOPT_CONNECTTIMEOUT, 20); curl_setopt($ch,CURLOPT_POST, 1); $data = curl_exec($ch); $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE); curl_close($ch); if($httpCode != '200'){ return json(['code'=>0,'msg'=>'连接服务器失败,稍后重试...']); } $versions = json_decode($data); //判断状态 $version_code = $versions->code; if($version_code == 0){ return json(['code'=>$version_code,'msg'=>$versions->msg]); } //版本比较 $version_num = $versions->version; $up_num =$versions->up_num; $res = version_compare($version_num,$this->sys_version_num,'>'); if($res){ return json(['code'=>1,'msg'=>'发现新版本','version'=>$version_num,'upnum'=>$up_num]); } else { return json(['code'=>0,'msg'=>'暂时还没更新哦! ==8']); } } /** * 自动更新 */ public function upload() { $data = Request::param(); if(empty($data['key'])){ return json(["code"=>0,"msg"=>"请配置正确升级key"]); } $url = $data['url'].'?domain='.Request::domain().'&key='.$data['key'].'&ver='.$this->sys_version_num; $ch =curl_init (); curl_setopt($ch,CURLOPT_URL, $url); curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch,CURLOPT_CONNECTTIMEOUT, 20); curl_setopt($ch,CURLOPT_POST, 1); $data = curl_exec($ch); $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE); curl_close($ch); if($httpCode != '200'){ return json(['code'=>0,'msg'=>'连接服务器失败,稍后重试...']); } //获取远程文件 $versions = json_decode($data); //判断状态 $version_code = $versions->code; if($version_code == 0){ return json(['code'=>$version_code,'msg'=>$versions->msg]); } $version_num = $versions->version; $file_url = $versions->src; //判断远程文件是否可用存在 $header = get_headers($file_url, true); if(!isset($header[0]) && (strpos($header[0], '200') || strpos($header[0], '304'))){ return json(["code"=>0,"msg"=>"获取远程文件失败"]); } if(!is_dir($this->upload_dir)){ $this->create_dirs($this->upload_dir); } //把远程文件放入本地 $package_file = $this->upload_dir.'tao_'.$version_num.'.zip'; $cpfile = copy($file_url,$package_file); if(!$cpfile) { return json(["code"=>0,"msg"=>"下载升级文件失败"]); } //记录下日志 $this->save_log("上传升级包成功!"); $this->update_progress("20%"); //升级前备份代码 $ex = array('app','view'); $backup_code_res = $this->copydir('../', $this->backup_dir, $ex); if(!$backup_code_res){ $this->save_log("备份失败!"); return json(["code"=>0,"msg"=>"备份失败"]); } $this->update_progress("30%"); //执行升级 $upres = $this->execute_update($package_file); //更新版本 Db::name('system')->update(['sys_version_num'=>$version_num,'id'=>1]); if($upres){ return json(["code"=>1,"msg"=>"升级成功"]); }else { return json(["code"=>0,"msg"=>"升级失败"]); } } /** * 处理升级包上传 */ public function uploadZip() { $files = request()->file('file'); if($files) { $name = $files->getOriginalName(); if(!$name) { return json(["code"=>0,"msg"=>"请上传升级包文件"]); } } //校验后缀 $astr = explode('.',$name); $ext = array_pop($astr); if($ext != 'zip') { return json(["code"=>0,"msg"=>"请上传文件格式不对"]); } //对比版本号 $astr = explode('_',$name); $version_num = str_replace(".zip", '',array_pop($astr)); //var_dump($version_num); if(!$version_num) { return json(["code"=>0,"msg"=>"获取版本号失败"]); } //对比 if(!$this->compare_version($version_num)) { return json(["code"=>0,"msg"=>"版本升级不能降级!请检查..."]); } if(!is_dir($this->upload_dir)){ $this->create_dirs($this->upload_dir); } $package_file = $this->upload_dir.$name; //$mv = $files->move('/../tmp/web/upload_dir',$version_num); $mfile = move_uploaded_file($files,$package_file); if(!$mfile) { return json(["code"=>0,"msg"=>"上传文件失败"]); } //记录下日志 $this->save_log("上传升级包成功!"); $this->update_progress("20%"); //升级前备份代码 $ex = array('app','view'); $backup_code_res = $this->copydir('../', $this->backup_dir, $ex); if(!$backup_code_res){ $this->save_log("备份失败!"); return json(["code"=>0,"msg"=>"备份失败"]); } $this->update_progress("30%"); //执行升级 $upres = $this->execute_update($package_file); //更新版本 Db::name('system')->update(['sys_version_num'=>$version_num,'id'=>1]); if($upres){ return json(["code"=>1,"msg"=>"升级成功"]); }else { return json(["code"=>0,"msg"=>"升级失败"]); } } /** * 升级操作 * @return [type] [description] */ private function execute_update($package_file) { //解压 如何使用zip加密压缩,这里解压缩的时候注意要解密 $uzip = new Uzip(); $unzip_res = $uzip->uzip($package_file,$this->upload_dir,true); if(!$unzip_res) { $this->save_log("解压失败"); return json(["code"=>0,"msg"=>"解压失败"]); } //解压成功,得到文件夹 $package_name = str_replace(".zip","",$package_file); //var_dump($package_name); $this->update_progress("50%"); /* //升级mysql if(file_exists($this->upload_dir.'/'.$package_file."/mysql/mysql_update.sql")) { $result = $this->database_operation($this->upload_dir.'/'.$package_file."/mysql/mysql_update.sql"); if(!$result['code']) { echo json($result);die; } } */ $this->update_progress("70%"); if(is_dir($package_name.'/')) { //升级PHP $cp_res = $this->copydir($package_name.'/', $this->root_dir); if(!$cp_res) { $this->save_log("php更新失败"); //数据库回滚 if(file_exists($this->upload_dir.'/'.$package_file."/mysql/mysql_rockback.sql")) { $this->save_log("数据库回滚"); $this->database_operation($this->upload_dir.'/'.$package_file."/mysql/mysql_rockback.sql"); } //php代码回滚 升级前备份的代码 $backup_code_res = $this->copydir($this->backup_dir, $this->zip_dir); if($backup_code_res){ $this->save_log("php回滚"); return json(["code"=>0,"msg"=>"php更新失败"]); } } } //把解压的升级包清除 //$del_zip = unlink($package_file); $this->delDirAndFile($this->upload_dir); $this->delDirAndFile($this->backup_dir); $this->update_progress("100%"); //更新系统的版本号了 //更新php的版本号了(应该跟svn/git的版本号一致) //更新数据库的版本号了(应该跟svn/git的版本号一致) return true; } /** * 比较代码版本 * @return [type] [description] */ private function compare_version($version_num='1.0.0') { return version_compare($version_num,$this->sys_version_num,'>'); //return json(['code'=>1,'msg'=>'版本','data'=>$version]); } /** * 数据库操作 */ public function database_operation($file) { $mysqli = new mysqli("localhost","root","root","test"); if($mysqli->connect_errno) { return json(["code"=>0,"msg"=>"Connect failed:".$mysqli->connect_error]); } $sql = file_get_contents($file); $a = $mysqli->multi_query($sql); return ["code"=>1,"msg"=>"数据库操作OK"]; } /** * 返回系统升级的进度 */ public function update_progress($progress) { exec(" echo '".$progress."' > $this->progress_log "); } /** * 记录日志 */ public function save_log($msg,$action="update") { $msg .= date("Y-m-d H:i:s").":".$msg."\n"; if($action == "update") { exec(" echo '".$msg."' >> $this->update_log "); }else { exec(" echo '".$msg."' >> $this->return_log "); } } /** * 复制文件夹$source下的文件和子文件夹下的内容到$dest下 升级+备份代码 * @param $source * @param $dest * @param $ex 定义指定复制的目录,默认全复制 */ public function copydir($source, $dest, $ex=array()) { if (!file_exists($dest)) mkdir($dest); if($handle = opendir($source)){ while (($file = readdir($handle)) !== false) { if (( $file != '.' ) && ( $file != '..' )) { if ( is_dir($source . $file) ) { if(count($ex) != 0){ if(in_array($file,$ex)){ $this->copydir($source . $file.'/', $dest . $file.'/'); } }else{ $this->copydir($source . $file.'/', $dest . $file.'/'); } } else { copy($source. $file, $dest . $file); } } } closedir($handle); } else { return false; } return true; } /** * 删除文件夹及内容 * @param $dirPath * @param $nowDir 是否删除当前文件夹$dirPath true false */ public function delDirAndFile( $dirPath, $nowDir=false ) { if ( $handle = opendir($dirPath) ) { while ( false !== ( $item = readdir( $handle ) ) ) { if ( $item != '.' && $item != '..' ) { $path = $dirPath.$item; //var_dump($path); if (is_dir($path)) { $this->delDirAndFile($path.'/'); rmdir($path.'/'); } else { unlink($path); } } } closedir( $handle ); /* if($nowDir == true){ if(!rmdir($dirPath)){ return false; } } */ } else { return false; } return true; } //创建多文件夹 public function create_dirs($path) { if (!is_dir($path)) { $directory_path = ""; $directories = explode("/",$path); array_pop($directories); foreach($directories as $directory) { $directory_path .= $directory."/"; if (!is_dir($directory_path)) { mkdir($directory_path); chmod($directory_path, 0777); } } } } }