likes
comments
collection
share

解放双手,不想用ftp和版本控制软件,自己用php做一个在线更新网站功能,用版本号作对比下用于在后台直接上传zip包后c

作者站长头像
站长
· 阅读数 65
no
yes
no
yes
备份完成
更新完成检测
验证token
检测是否有更新?
暂无更新
退出
下载新包
需要备份?
删除旧包文件
执行备份函数
解压新包
更新本地版本号

下用于在后台直接上传zip包后curd请求一次自动更新,这样安装包的管理能力更强,适用多个平台、多种环境的更新,就是偷懒不想一个一个平台登录ftp或者其它方式更新(自己用git、svn另说),在平台管理端可以个性的还原某个版本。

<?php

define('APP_UPDATE_DEBUG'true);//是否调试
if (APP_UPDATE_DEBUG) {
    error_reporting(E_ALL);//显示所有错误
    ini_set('display_errors''on');
else {
    error_reporting(0);//关闭所有错误
    ini_set('display_errors''off');
}

(new AppUpdate)->run();//执行

class AppUpdate
{
    const APP_UPDATE_API 'https://abc.com/app_version';//更新接口
    const APP_UPDATE_TYPE 'h5';//更新平台
    const APP_UPDATE_SECRET 'jx5HTGJiNq8U2BmzYwKbRoLtyd6Drp7C';//密钥
    const APP_UPDATE_TOKEN_TYPE 'md5';//token验证方式
    const APP_UPDATE_DELETE_DIR = ['/static/''/uni_modules/'];//删除目录
    const APP_UPDATE_NEED_BACKUP false;//是否备份
    const APP_UPDATE_BACKUP_DIR '/backup/';//备份目录
    const APP_UPDATE_UNNEED_FILE = ['.''..''.user.ini''.idea''.well-known''.htaccess''.nginx.htaccess''version'];//不用压缩的文件

    //验证token
    private static function check_token()
    {
        $token = !empty($_REQUEST['token']) ? $_REQUEST['token'] : '';
        if (!$token) {
            self::run_exit('token is empty');
        }
        //自定义验证token
        $method self::APP_UPDATE_TOKEN_TYPE;
        if ($token != $method(self::APP_UPDATE_SECRET)) {
            self::run_exit('token is error');
        }
    }

    //执行
    public function run()
    {
        self::check_token();
        $version = (int)@file_get_contents(__DIR__ . '/version');
        $version $version 0 ? $version 100;
        //更新检测接口
        $url self::APP_UPDATE_API . '?type=' . self::APP_UPDATE_TYPE . '&version=' . $version;
        $res $this->get($url);
        if (empty($res) || $res['status'] == 200) {
            self::run_exit('没有更新');
        }
        $info $res['data'];
        if ($info['version'] <= $version || empty($info['url'])) {
            self::run_exit('无须更新');
        }
        //下载更新包
        $fileName __DIR__ . '/new' . $info['version'] . '.zip';
        $file $this->remote2local($info['url'], $fileName);
        if (!file_exists($fileName)) {
            self::run_exit('下载失败');
        }
        //执行备份
        if (self::APP_UPDATE_NEED_BACKUP) {
            $this->backup();
        }

        // 要删除目录
        if (!empty(self::APP_UPDATE_DELETE_DIR)) {
            foreach (self::APP_UPDATE_DELETE_DIR as $dir) {
                $this->deleteDirectory(__DIR__ . $dir);
            }
        }

        $zip new \ZipArchive ();
        $zip->open($fileName);
        $decode $zip->extractTo(__DIR__ . '/');
        $zip->close();
        if (!$decode) {
            self::run_exit('解压失败');
        }
        //更新版本号
        @file_put_contents(__DIR__ . '/version'$info['version']);
        @unlink($fileName);//删除压缩包
        self::run_exit('升级成功');
    }


    //输出
    private static function run_exit($msg)
    {
        exit($msg);
    }

    //获取远程文件
    private function get($url)
    {
        $headerArray = ["Content-type:application/json;""Accept:application/json"];
        $ch curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        if (APP_UPDATE_DEBUG) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);
        $output curl_exec($ch);

        if (curl_errno($ch)) {
            self:: run_exit(curl_error($ch));
        }
        curl_close($ch);
        if (stripos($output'{') === 0) {
            return json_decode($outputtrue);
        }
        return $output;
    }

    //删除目录
    private function deleteDirectory($directoryPath)
    {
        if (!is_dir($directoryPath)) {
            return;
        }
        $iterator new \RecursiveDirectoryIterator($directoryPath\RecursiveDirectoryIterator::SKIP_DOTS);
        $iterator new \RecursiveIteratorIterator($iterator\RecursiveIteratorIterator::CHILD_FIRST);
        foreach ($iterator as $file) {
            $file->isFile() ? unlink($file->getRealPath()) : rmdir($file->getRealPath());
        }
        rmdir($directoryPath);
    }

    //备份旧文件
    private function backup()
    {
        $dir __DIR__ . self::APP_UPDATE_BACKUP_DIR;
        if (!is_dir($dir)) {
            @mkdir($dir0777true);
        }
        if (!is_writeable($dir)) {
            self::run_exit('备份目录没有写入权限');
        }
        $zipName $dir date('YmdHi') . '.zip';
        $zip new \ZipArchive ();
        $zip->open($zipName\ZipArchive::CREATE);
        $this->createZip(opendir($dir), $zip$dir);
        $zip->close();
        if (!file_exists($zipName)) {
            self::run_exit('备份失败');
        }
    }

    //远程文件转本地文件
    private function remote2local($url$localPath)
    {
        $ch curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        //开发环境取消ssl认证
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $res curl_exec($ch);
        if (curl_errno($ch)) {
            return false;
        }
        curl_close($ch);
        //保存到本地
        $file fopen($localPath'w');
        fwrite($file$res);
        fclose($file);
        return $localPath;
    }


    //递归创建压缩包
    private function createZip($openFile$zipObj$sourcePath$newRelat '')
    {
        while (($file readdir($openFile)) != false) {
            if (in_array($fileself::APP_UPDATE_UNNEED_FILE)) {
                continue;
            }
            //跳过压缩包,主要是备份的文件
            if (substr($file, -4) == '.zip'continue;
            /*源目录路径(绝对路径)*/
            $sourceTemp $sourcePath '/' . $file;
            /*目标目录路径(相对路径)*/
            $newTemp $newRelat == '' ? $file $newRelat '/' . $file;
            if (is_dir($sourceTemp)) {
                $zipObj->addEmptyDir($newTemp);
                $this->createZip(opendir($sourceTemp), $zipObj$sourceTemp$newTemp);
            }
            if (is_file($sourceTemp)) {
                $zipObj->addFile($sourceTemp$newTemp);
            }
        }
    }
}

未经测试,请勿用于生产环境,谢谢。 要php7以上才行哦,自己做好user.ini控制,让php能够执行指定目录,也可以通过nginx反向代理执行某个php文件。

转载自:https://juejin.cn/post/7418118194341937171
评论
请登录