一个在线更新web、h5的包,简单易用的方法是使用FTP工具或者Git进行版本控制和更新。
方法一:使用FTP工具
1. 使用FTP客户端(如FileZilla)连接到服务器。
2. 浏览到需要更新的文件所在的目录。
3. 将本地文件上传到服务器上对应的目录。
4. 删除服务器上的旧文件。
5. 将新文件从本地复制到服务器上对应的目录。
方法二:使用Git
1. 在本地创建一个Git仓库,并将需要更新的文件添加到仓库中。
2. 在服务器上安装Git并配置好远程仓库地址。
3. 将本地仓库推送到远程仓库。
4. 在服务器上拉取远程仓库的最新代码。
5. 将新文件部署到服务器上对应的目录。
这两种方法都可以实现在线更新web、h5安装包,下面写了一个用php实现这种功能,用于在后台直接上传zip包后curd请求一次自动更新,这样安装包的管理能力更强。
方法三:
<?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($output, true);
}
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($dir, 0777, true);
}
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($file, self::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);
}
}
}
}