dggzichahu/application/admin/logic/UpgradeLogic.php

433 lines
13 KiB
PHP
Executable File

<?php// +----------------------------------------------------------------------
// | 宏驰云科技开发团队 版权所有 拥有最终解释权
// +----------------------------------------------------------------------
// | Author: HcyShop-松鼠
// +----------------------------------------------------------------------
namespace app\admin\logic;
use think\Db;
use Requests;
use think\Exception;
use think\facade\Cache;
use think\facade\Log;
class UpgradeLogic
{
protected static $base_url = 'https://shop.likemarket.net';
/**
* Notes: 版本列表
* @param $page_no
* @param $page_size
* @author 竹
* @return array
*/
public static function index($page_no, $page_size)
{
$lists = self::getRemoteVersion($page_no, $page_size) ?? [];
if (empty($lists)) {
return ['count' => 0, 'lists' => []];
}
$local_data = local_version();
$local_version = $local_data['version'];
foreach ($lists as $k => $item) {
$lists[$k]['version_str'] = '';
$lists[$k]['able_update'] = 0;
if ($local_version == $item['version_no']) {
$lists[$k]['version_str'] = '您的系统当前处于此版本';
}
if ($local_version < $item['version_no']) {
$lists[$k]['version_str'] = '系统可更新至此版本';
$lists[$k]['able_update'] = 1;
}
//最新的版本号标志
$lists[$k]['new_version'] = 0;
$lists[0]['new_version'] = 1;
//注意,是否需要重新发布描述
$lists[$k]['notice'] = '';
if ($item['is_republish'] == 1) {
$lists[$k]['notice'] = '更新至当前版本后需重新发布前端商城';
}
//处理更新内容信息
$contents = $item['update_content'];
$add = [];
$optimize = [];
$repair = [];
if (!empty($contents)) {
foreach ($contents as $content) {
if ($content['type'] == 1) {
$add[] = '新增:'.$content['update_function'];
}
if ($content['type'] == 2) {
$optimize[] = '优化:'.$content['update_function'];
}
if ($content['type'] == 3) {
$repair[] = '修复:'.$content['update_function'];
}
}
}
$lists[$k]['add'] = $add;
$lists[$k]['optimize'] = $optimize;
$lists[$k]['repair'] = $repair;
unset($lists[$k]['update_content']);
}
return ['count' => count($lists), 'lists' => $lists];
}
/**
* Notes: 获取远程数据
* @param string $page_no
* @param string $page_size
* @author 竹
* @return mixed
*/
public static function getRemoteVersion($page_no = '', $page_size = '')
{
$cache_version = Cache::get('version_lists');
if (!empty($cache_version)) {
return $cache_version;
}
if (empty($page_no) || empty($page_size)) {
$remote_url = self::$base_url."/api/version/lists?type=2";
} else {
$remote_url = self::$base_url."/api/version/lists?type=2&page_no=$page_no&page_size=$page_size";
}
$result = Requests::get($remote_url);
$result = json_decode($result->body, true);
$result = $result['data'] ?? [];
Cache::set('version_lists', $result, 1800);
return $result;
}
/**
* Notes: 更新主程序
* @param $version
* @return bool|string
* @author 竹
*/
public static function upgrade($post)
{
$post['update_type'] = 1;
Db::startTrans();
try {
//修改旧数据
self::handleOldData();
//要更新的版本
$version = $post['version_no'];
//远程下载链接
$remote_url = $post['package_link'];
// 本地更新路径
$local_upgrade_dir = ROOT_PATH . '/upgrade/';
// 本地更新包路径
$path = ROOT_PATH . '/upgrade/';
// 本地更新临时文件
$temp_dir = $path . 'temp/';
if (!is_dir($path)) {
mkdir(iconv("UTF-8", "GBK", $path), 0777, true);
}
//下载更新压缩包保存到本地
$remote_data = self::downFile($remote_url, $local_upgrade_dir);
if (false === $remote_data) {
throw new Exception('获取文件错误');
}
//解压缩
if (false === unzip($remote_data['save_path'], $temp_dir)) {
throw new Exception('解压文件错误');
}
//更新sql
if (false === self::upgradeSql($temp_dir . 'sql/')) {
throw new Exception('更新数据库失败');
}
//更新文件
if (false === self::upgradeDir($temp_dir . 'project/', self::getProjectPath())) {
throw new Exception('更新文件失败');
}
//更新本地版本号文件
$upgrade_data = ['version' => $version];
if (false === self::upgradeVersion($upgrade_data)) {
throw new Exception('本地更新日志写入失败');
}
//删除临时文件(压缩包不删除,删除解压的文件)
if (false === del_target_dir($temp_dir, true)) {
Log::write('删除临时文件失败');
}
Db::commit();
//增加日志
self::addlog($post);
return true;
} catch (Exception $e) {
Db::rollback();
//错误日志
$post['error'] = $e->getMessage();
self::addlog($post, false);
//删除临时文件(压缩包不删除,删除解压的文件)
if (false === del_target_dir($temp_dir, true)) {
Log::write('删除临时文件失败');
}
return $e->getMessage();
}
}
/**
* Notes: 添加日志
* @param $data
* @param bool $status
* @author 竹
* @return bool|\Requests_Response
*/
public static function addlog($data, $status = true)
{
$log_msg = json_encode($data, JSON_UNESCAPED_UNICODE);
Log::write('更新日志:'.$log_msg);
try{
$data = [
'version_id' => $data['id'],
'version_no' => $data['version_no'],
'ip_address' => get_client_ip(),
'domain' => request()->domain(),
'type' => 2,
'update_type' => $data['update_type'],
'status' => $status ? 1 : 0,
'error' => $data['error'] ?? '未知错误'
];
$request_url = self::$base_url.'/api/version/log';
return Requests::post($request_url, [], $data);
} catch(\Exception $e) {
Log::write('更新日志添加失败:'.$e->getMessage());
return false;
}
}
/**
* Notes: 下载压缩包
* @param $url
* @param string $savePath
* @return array|bool
* @author 竹
*/
public static function downFile($url, $savePath = './upgrade/')
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, TRUE); //需要response header
curl_setopt($ch, CURLOPT_NOBODY, FALSE); //需要response body
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$header = '';
$body = '';
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') {
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); //头信息size
$header = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
}
curl_close($ch);
//文件名
$fullName = basename($url);
//文件保存完整路径
$savePath = $savePath . $fullName;
//创建目录并设置权限
$basePath = dirname($savePath);
if (!file_exists($basePath)) {
@mkdir($basePath, 0777, true);
@chmod($basePath, 0777);
}
if (file_put_contents($savePath, $body)) {
return [
'save_path' => $savePath,
'file_name' => $fullName,
];
}
return false;
}
/**
* Notes: 获取项目路径
* @return string
* @author 竹
*/
public static function getProjectPath()
{
$path = dirname(ROOT_PATH);
$path = trim(str_replace('server', '', $path));
return $path;
}
/**
* Notes: 执行指定文件夹内的sql文件
* @param $dir
* @return bool
* @author 竹
*/
public static function upgradeSql($dir)
{
//遍历指定目录下的指定后缀文件
$sql_files = get_scandir($dir, '', 'sql');
if (false === $sql_files) {
return false;
}
//当前数据库前缀
$sql_prefix = config('database.prefix');
//遍历更新sql
foreach ($sql_files as $k => $sql_file) {
if (get_extension($sql_file) != 'sql') {
continue;
}
$sql_content = file_get_contents($dir . $sql_file);
if (empty($sql_content)) {
continue;
}
$sqls = explode(';', $sql_content);
//执行sql
foreach ($sqls as $sql) {
if (!empty($sql)) {
$sql = str_replace('`ls_', '`' . $sql_prefix, $sql);
Db::execute($sql . ';');
}
}
}
return true;
}
/**
* Notes: 更新文件
* @param $temp_file //临时更新文件路径 (新的更新文件)
* @param $old_file //需要更新的文件路囧 (旧的文件)
* @author 竹
* @return array|bool
*/
public static function upgradeDir($temp_file, $old_file)
{
if (!file_exists($temp_file)) {
return [];
}
if (empty(trim($temp_file)) || empty(trim($old_file))) {
return false;
}
// 目录不存在就新建
if (!is_dir($old_file)) {
mkdir($old_file, 0777, true);
}
foreach (glob($temp_file . '*') as $file_name) {
// 要处理的是目录时,递归处理文件目录。
if (is_dir($file_name)) {
self::upgradeDir($file_name . '/', $old_file . basename($file_name) . '/');
}
// 要处理的是文件时,判断是否存在 或者 与原来文件不一致 则覆盖
if (is_file($file_name)) {
if (!file_exists($old_file . basename($file_name))
|| md5(file_get_contents($file_name)) != md5(file_get_contents($old_file . basename($file_name)))
) {
copy($file_name, $old_file . basename($file_name));
}
}
}
return true;
}
/**
* Notes: 更新本地版本号
* @param $data
* @return bool
* @author 竹
*/
public static function upgradeVersion($data)
{
$version = './upgrade/version.json';
$res = file_put_contents($version, json_encode($data, JSON_UNESCAPED_UNICODE));
if (empty($res)) {
return false;
}
return true;
}
/**
* Notes: 修改旧数据
* @author 竹
* @throws Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public static function handleOldData()
{
try {
//修改旧活动专区错误
$temp = [];
$count = 0;
$lists = Db::name('activity_goods')->where(['del' => 0])->select();
foreach ($lists as $k => $v) {
$temp_key = $v['goods_id'].'_'.$v['activity_id'];
if (in_array($temp_key, $temp)) {
Db::name('activity_goods')
->where(['del' => 0, 'id' => $v['id']])
->update(['del' => 1]);
$count += 1;
} else {
$temp[] = $temp_key;
}
}
if ($count > 0) {
Log::write('处理活动专区错误,删除'.$count.'数据');
}
// 更新file_cate表中type=null值的旧记录
$handle_file = Db::name('file_cate')->whereNull('type')->update(['type' => 1]);
if ($handle_file) {
Log::write('更新file_cate表中type=null值的旧记录');
}
} catch (\Exception $e) {
Log::write('修改旧数据错误:'.$e->getMessage());
}
}
}