美文网首页
php 实现一个简单的项目升级功能

php 实现一个简单的项目升级功能

作者: 胡乱唱歌ing | 来源:发表于2019-01-03 10:04 被阅读0次

    思路

    1.制作升级包,增量更新
    2.升级包上传验证上传文件,验证当前系统版本
    3.升级之前要先备份原来的代码,升级失败要进行回滚
    4.记录升级日志,返回升级进度
    5.升级包应该是加密的(暂时没实现)

    说明

    1.升级包的目录结构必须如下

    /**
     *  升级包规定的目录结构
     *  xxx_版本号.zip(如:xxx_1.0.0.zip)
     *   |
     *   |————mysql
     *   |    |
     *   |    |___mysql_update.sql(更新脚本)
     *   |    |___mysql_rockback.sql(回滚脚本)
     *   |    
     *   |____php
     * 
    */
    

    2.mysql_update.sql

    create table test(id init(11));
    create table test2(id init(11));
    
    1. mysql_rockback.sql
    drop table test;
    drop table test2;
    

    4.代码

    class UpgradeSys{
        public $update_log = "/tmp/web/update_log.log"; //系统升级日志
        public $return_log = "/tmp/web/return_log.log"; //系统回滚日志
        public $progress_log = "/tmp/web/progress_log.log"; //记录进度
        public $root_dir = "/Users/feng/Documents/work/test"; //站点代码的根目录
        public $aFile = ["log","runtime"];//忽略文件夹相对路径
        public $backup_dir = "/tmp/web/backup_dir";//备份目录
        public $upload_dir = "/tmp/web/upload_dir";//升级包目录
        public $sys_version_num = '1.0.0';//当前系统的版本 这个在实际应用中应该是虫数据库获取得到的,这里只是举个例子
        /** 展示升级界面 */
        public function index()
        {
            include("update.html");
        }
    
        /**
         * 处理升级包上传
         */
        public function upload()
        {
            $params = $_POST;
            if($_FILES)
            {
                $name  = $_FILES['file']['tmp_name'];
                if(!$name || !is_uploaded_file($name))
                {
                    echo json_encode(["status"=>0,"msg"=>"请上传升级包文件"]);
                    die;
                }
            }
            //校验后缀
            $astr = explode('.',$name);
            $ext = array_pop($astr);
            if($ext != 'zip')
            {
                echo json_encode(["status"=>0,"msg"=>"请上传文件格式不对"]);
                die;
            }
    
            //校验升级密码
            // if(!isset($params['password']) || $params['password'] != $this->password)
            // {
            //     echo json_encode(["status"=>0,"msg"=>"密码错误"]);
            //     die;
            // }
            //对比版本号
            $astr = explode('_',$name);
            $version_num = str_replace(".zip", '',array_pop($astr));
            if(!$version_num)
            {
                echo json_encode(["status"=>0,"msg"=>"获取版本号失败"]);
                die;
            }
            //对比
            if(!$this->compare_version($version_num))
            {
                echo json_encode(["status"=>0,"msg"=>"不能升级低版本的"]);
                die;
            }
            $package_name = $this->upload_dir.'/'.$version_num.'.zip';
            if(!move_uploaded_file($name,$package_name))
            {
                echo json_encode(["status"=>0,"msg"=>"上传文件失败"]);
                die;
            }
    
            //记录下日志
            $this->save_log("上传升级包成功!");
            $this->update_progress("20%");
            //备份code
            $result = $this->backup_code();
            if(!$result)
            {
                $this->save_log("备份失败!");
                echo json_encode(["status"=>0,"msg"=>"备份失败"]);
                die;
            }
            $this->update_progress("30%");
            //执行升级
            $this->execute_update($package_name);
        }
    
        /**
         * 升级操作
         * @return [type] [description]
         */
        private function execute_update($package_name)
        {
            //解压 如何使用zip加密压缩,这里解压缩的时候注意要解密
            exec(" cd $upload_dir && unzip $package_name ");
            $package_name = str_replace(".zip","",$package_name);
            if(!is_dir($package_name))
            {
                $this->save_log("解压失败");
                echo json_encode(["status"=>0,"msg"=>"解压失败"]);
                die;
            }
            $this->update_progress("50%");
            //升级mysql
            if(file_exists($this->upload_dir.'/'.$package_name."/mysql/mysql_update.sql"))
            {
                $result = $this->database_operation($this->upload_dir.'/'.$package_name."/mysql/mysql_update.sql");
                if(!$result['status'])
                {
                    echo json_encode($result);die;
                }
            }
            $this->update_progress("70%");
            //升级PHP
            if(is_dir($this->upload_dir.'/'.$package_name.'/php'))
            {
                exec("cd {$this->upload_dir}/{$package_name}/php && cp -rf ./* $this->root_dir ",$mdata,$status);
                if($status != 0 )
                {
                    $this->save_log("php更新失败");
                    //数据库回滚
                    if(file_exists($this->upload_dir.'/'.$package_name."/mysql/mysql_rockback.sql"))
                    {
                        $this->save_log("数据库回滚");
                        $this->database_operation($this->upload_dir.'/'.$package_name."/mysql/mysql_rockback.sql");
                     
                    }
                    //php代码回滚
                    $cmd = "cp -rf " .$this->backup_dir."/".$this->sys_version_num.'/'.basename($this->root_dir)."/* ".$this->root_dir;
                    exec($cmd,$mdata,$status);
                    $this->save_log("php回滚");
                    echo json_encode(["status"=>0,"msg"=>"php更新失败"]);
                    die;
                }
            }
            //把解压的升级包清除
            exec("rm -rf $upload_dir/$package_name ");
            
            $this->update_progress("100%");
            //更新系统的版本号了
           //更新php的版本号了(应该跟svn/git的版本号一致)
           //更新数据库的版本号了(应该跟svn/git的版本号一致)
            echo json_encode(["status"=>1,"msg"=>"升级成功"]);
            die;
        }
    
        /**
         * 比较代码版本
         * @return [type] [description]
         */
        private function compare_version($version_num='1.0.0')
        {
            
            return version_compare($version_num,$this->sys_version_num,'>');
        }
    
        /**
         * 备份代码
         */
        private function backup_code()
        {
            //rsync 要确定系统是否已经安装
            $cmd = "cd $root_dir && cd ..  && rsync -av ";
            foreach ($this->aFile as $key => $value) {
                $cmd ."--exclude ". basename($this->root_dir) ."/".$value ." ";
            }
            $cmd .= basename($this->root_dir)." ".$this->backup_dir."/".$this->sys_version_num;
            exec($cmd,$mdata,$status);
            if($status != 0)
            {
                return false;
            }
            //这里还可以对备份的文件进行压缩
            return true;
        }
    
        /**
         * 数据库操作
         */
        public function database_operation($file)
        {
            $mysqli = new mysqli("localhost","root","root","test");
            if($mysqli->connect_errno)
            {
                return ["status"=>0,"msg"=>"Connect failed:".$mysqli->connect_error];
            }
            $sql = file_get_contents($file);
            $a = $mysqli->multi_query($sql);
            return ["status"=>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 ");
            }
        }
    
    }
    

    相关文章

      网友评论

          本文标题:php 实现一个简单的项目升级功能

          本文链接:https://www.haomeiwen.com/subject/kvctrqtx.html