vr-shopxo-source/app/service/ThemeService.php

476 lines
15 KiB
PHP
Raw Normal View History

2018-12-28 10:58:37 +00:00
<?php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
2021-03-16 02:34:52 +00:00
// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved.
2018-12-28 10:58:37 +00:00
// +----------------------------------------------------------------------
2021-03-16 02:34:52 +00:00
// | Licensed ( https://opensource.org/licenses/mit-license.php )
2018-12-28 10:58:37 +00:00
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
namespace app\service;
2021-07-18 15:42:10 +00:00
use think\facade\Db;
2021-02-15 14:45:33 +00:00
use app\service\ResourcesService;
2018-12-28 10:58:37 +00:00
/**
* 主题服务层
* @author Devil
* @blog http://gong.gg/
* @version 0.0.1
* @datetime 2016-12-01T21:51:08+0800
*/
class ThemeService
{
// 静态目录和html目录
2021-07-30 03:35:25 +00:00
private static $html_path = 'app'.DS.'index'.DS.'view'.DS;
private static $static_path = 'public'.DS.'static'.DS.'index'.DS;
2018-12-28 10:58:37 +00:00
2020-08-15 03:25:48 +00:00
// 排除的文件后缀
private static $exclude_ext = ['php'];
2020-08-15 03:25:48 +00:00
2020-11-21 08:42:35 +00:00
/**
* 默认主题标识符
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-20
* @desc description
*/
public static function DefaultTheme()
{
return MyC('common_default_theme', 'default', true);
}
2018-12-28 10:58:37 +00:00
/**
* 获取模板列表
* @author Devil
* @blog http://gong.gg/
* @version 0.0.1
* @datetime 2017-05-10T10:24:40+0800
* @param [array] $params [输入参数]
* @return [array] [模板列表]
*/
public static function ThemeList($params = [])
2018-12-28 10:58:37 +00:00
{
$result = [];
$dir = ROOT.self::$html_path;
2018-12-28 10:58:37 +00:00
if(is_dir($dir))
{
if($dh = opendir($dir))
{
2019-01-11 09:35:35 +00:00
$default_preview = __MY_PUBLIC_URL__.'static'.DS.'common'.DS.'images'.DS.'default-preview.jpg';
2018-12-28 10:58:37 +00:00
while(($temp_file = readdir($dh)) !== false)
{
2020-11-21 08:42:35 +00:00
if(substr($temp_file, 0, 1) == '.' || in_array($temp_file, ['index.html']))
2019-01-11 09:35:35 +00:00
{
continue;
}
2018-12-28 10:58:37 +00:00
$config = $dir.$temp_file.DS.'config.json';
if(!file_exists($config))
{
continue;
}
// 读取配置文件
$data = json_decode(file_get_contents($config), true);
if(!empty($data) && is_array($data))
{
if(empty($data['name']) || empty($data['ver']) || empty($data['author']))
{
continue;
}
$preview = ROOT.self::$static_path.$temp_file.DS.'images'.DS.'preview.jpg';
2018-12-28 10:58:37 +00:00
$result[] = array(
'theme' => $temp_file,
'name' => htmlentities($data['name']),
'ver' => str_replace(array('',','), ', ', htmlentities($data['ver'])),
'author' => htmlentities($data['author']),
'home' => isset($data['home']) ? $data['home'] : '',
2019-01-11 09:35:35 +00:00
'preview' => file_exists($preview) ? __MY_PUBLIC_URL__.'static'.DS.'index'.DS.$temp_file.DS.'images'.DS.'preview.jpg' : $default_preview,
2018-12-28 10:58:37 +00:00
'is_delete' => ($temp_file == 'default') ? 0 : 1,
);
}
}
closedir($dh);
}
}
return $result;
}
/**
* 模板上传
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-19T00:53:45+0800
* @param [array] $params [输入参数]
*/
public static function ThemeUpload($params = [])
2018-12-28 10:58:37 +00:00
{
// 文件上传校验
$error = FileUploadError('theme');
if($error !== true)
{
return DataReturn($error, -1);
}
// 文件格式化校验
2021-02-15 14:45:33 +00:00
$type = ResourcesService::ZipExtTypeList();
2018-12-28 10:58:37 +00:00
if(!in_array($_FILES['theme']['type'], $type))
{
return DataReturn('文件格式有误请上传zip压缩包', -2);
}
2021-02-24 04:40:34 +00:00
// 上传处理
return self::ThemeUploadHandle($_FILES['theme']['tmp_name'], $params);
}
/**
* 模板上传处理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-17
* @desc description
* @param [string] $package_file [软件包地址]
* @param [array] $params [输入参数]
*/
public static function ThemeUploadHandle($package_file, $params = [])
{
2018-12-28 10:58:37 +00:00
// 目录是否有权限
if(!is_writable(ROOT.self::$html_path))
2018-12-28 10:58:37 +00:00
{
2020-08-15 03:25:48 +00:00
return DataReturn('视图目录没权限['.ROOT.self::$html_path.']', -10);
2018-12-28 10:58:37 +00:00
}
if(!is_writable(ROOT.self::$static_path))
2018-12-28 10:58:37 +00:00
{
2020-08-15 03:25:48 +00:00
return DataReturn('资源目录没权限['.self::$static_path.']', -10);
2018-12-28 10:58:37 +00:00
}
2019-02-14 03:33:41 +00:00
// 资源目录
$dir_list = [
'_html_' => ROOT.self::$html_path,
'_static_' => ROOT.self::$static_path,
];
2018-12-28 10:58:37 +00:00
// 开始解压文件
2021-08-11 09:30:06 +00:00
$zip = new \ZipArchive();
$resource = $zip->open($package_file);
if($resource != true)
2018-12-28 10:58:37 +00:00
{
2021-08-11 09:30:06 +00:00
return DataReturn('压缩包打开失败['.$resource.']', -11);
}
$success = 0;
for($i=0; $i<$zip->numFiles; $i++)
{
// 资源文件
$file = $zip->getNameIndex($i);
2018-12-28 10:58:37 +00:00
2021-08-11 09:30:06 +00:00
// 排除临时文件和临时目录
if(strpos($file, '/.') === false && strpos($file, '__') === false)
{
// 文件包对应系统所在目录
$is_has_find = false;
foreach($dir_list as $dir_key=>$dir_value)
2018-12-28 10:58:37 +00:00
{
2021-08-11 09:30:06 +00:00
if(strpos($file, $dir_key) !== false)
2018-12-28 10:58:37 +00:00
{
2021-08-11 09:30:06 +00:00
// 匹配成功文件路径处理、跳出循环
$new_file = str_replace($dir_key.'/', '', $dir_value.$file);
$is_has_find = true;
break;
2018-12-28 10:58:37 +00:00
}
2021-08-11 09:30:06 +00:00
}
2018-12-28 10:58:37 +00:00
2021-08-11 09:30:06 +00:00
// 没有匹配到则指定目录跳过
if($is_has_find == false)
{
continue;
}
2019-02-14 04:39:15 +00:00
2021-08-11 09:30:06 +00:00
// 排除后缀文件
$pos = strripos($file, '.');
if($pos !== false)
{
$info = pathinfo($file);
2022-02-05 07:48:08 +00:00
if(isset($info['extension']) && in_array(strtolower($info['extension']), self::$exclude_ext))
2020-08-15 03:25:48 +00:00
{
2021-08-11 09:30:06 +00:00
continue;
2020-08-15 03:25:48 +00:00
}
2021-08-11 09:30:06 +00:00
}
2020-08-15 03:25:48 +00:00
2021-08-11 09:30:06 +00:00
// 截取文件路径
$file_path = substr($new_file, 0, strrpos($new_file, '/'));
2018-12-28 10:58:37 +00:00
2021-08-11 09:30:06 +00:00
// 路径不存在则创建
if(!is_dir($file_path))
{
mkdir($file_path, 0777, true);
}
2018-12-28 10:58:37 +00:00
2021-08-11 09:30:06 +00:00
// 如果不是目录则写入文件
if(!is_dir($new_file))
{
// 读取这个文件
$stream = $zip->getStream($file);
if($stream !== false)
2018-12-28 10:58:37 +00:00
{
2021-08-11 09:30:06 +00:00
$file_content = stream_get_contents($stream);
if($file_content !== false)
{
if(file_put_contents($new_file, $file_content))
{
$success++;
}
}
fclose($stream);
2018-12-28 10:58:37 +00:00
}
}
}
}
2021-08-11 09:30:06 +00:00
// 关闭zip
$zip->close();
// 未匹配成功一个文件则认为插件包无效
if($success <= 0)
{
return DataReturn('无效的主题包', -1);
}
2021-02-24 04:40:34 +00:00
return DataReturn('安装成功', 0);
2018-12-28 10:58:37 +00:00
}
/**
* 模板删除
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-12-19T00:46:02+0800
* @param [array] $params [输入参数]
*/
public static function ThemeDelete($params = [])
2018-12-28 10:58:37 +00:00
{
2020-11-21 08:42:35 +00:00
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => '模板id有误',
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
2018-12-28 10:58:37 +00:00
{
2020-11-21 08:42:35 +00:00
return DataReturn($ret, -1);
2018-12-28 10:58:37 +00:00
}
2019-06-16 08:22:43 +00:00
// 防止路径回溯
2019-01-05 16:20:24 +00:00
$id = htmlentities(str_replace(array('.', '/', '\\', ':'), '', strip_tags($params['id'])));
2018-12-28 10:58:37 +00:00
if(empty($id))
{
return DataReturn('主题名称有误', -1);
}
// default不能删除
if($id == 'default')
{
return DataReturn('系统模板不能删除', -2);
}
// 不能删除正在使用的主题
2020-11-21 08:42:35 +00:00
if(self::DefaultTheme() == $id)
2018-12-28 10:58:37 +00:00
{
return DataReturn('不能删除正在使用的主题', -2);
}
// 开始删除主题
if(\base\FileUtil::UnlinkDir(ROOT.self::$html_path.$id) && \base\FileUtil::UnlinkDir(ROOT.self::$static_path.$id))
2018-12-28 10:58:37 +00:00
{
return DataReturn('删除成功');
}
return DataReturn('删除失败或资源不存在', -100);
}
2019-06-16 08:22:43 +00:00
/**
* 主题打包
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2019-03-22
* @desc description
* @param [array] $params [输入参数]
*/
public static function ThemeDownload($params = [])
{
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => '模板id有误',
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
// 是否开启开发者模式
2021-07-18 15:42:10 +00:00
if(MyConfig('shopxo.is_develop') !== true)
2019-06-16 08:22:43 +00:00
{
return DataReturn('请先开启开发者模式', -1);
}
// 防止路径回溯
$theme = htmlentities(str_replace(array('.', '/', '\\', ':'), '', strip_tags($params['id'])));
if(empty($theme))
{
return DataReturn('主题名称有误', -1);
}
2019-10-14 13:33:20 +00:00
// 获取配置信息
2021-04-23 08:43:23 +00:00
$config_res = self::ThemeConfig($theme);
if($config_res['code'] != 0)
2019-10-14 13:33:20 +00:00
{
2021-04-23 08:43:23 +00:00
return $config_res;
2019-10-14 13:33:20 +00:00
}
2021-04-23 08:43:23 +00:00
$config = $config_res['data'];
2019-10-14 13:33:20 +00:00
2019-06-16 08:22:43 +00:00
// 目录不存在则创建
$new_dir = ROOT.'runtime'.DS.'data'.DS.'theme_package'.DS.$theme;
\base\FileUtil::CreateDir($new_dir);
// 复制包目录 - 视图
$old_dir = ROOT.self::$html_path.$theme;
if(is_dir($old_dir))
{
if(\base\FileUtil::CopyDir($old_dir, $new_dir.DS.'_html_') != true)
{
return DataReturn('项目包复制失败[视图]', -2);
}
}
// 复制包目录 - 静态文件
$old_dir = ROOT.self::$static_path.$theme;
if(is_dir($old_dir))
{
if(\base\FileUtil::CopyDir($old_dir, $new_dir.DS.'_static_') != true)
{
return DataReturn('项目包复制失败[静态文件]', -2);
}
}
// 配置文件历史信息更新
$new_config_file = $new_dir.DS.'_html_'.DS.'config.json';
if(!file_exists($new_config_file))
{
return DataReturn('新配置文件有误', -10);
}
if(empty($config['history']))
{
$config['history'] = [];
}
$config['history'][] = [
'host' => __MY_HOST__,
'url' => __MY_URL__,
'ip' => __MY_ADDR__,
'time' => date('Y-m-d H:i:s'),
];
if(@file_put_contents($new_config_file, JsonFormat($config)) === false)
{
return DataReturn('新应用配置文件更新失败', -11);
}
2019-06-16 08:22:43 +00:00
// 生成压缩包
$zip = new \base\ZipFolder();
if(!$zip->zip($new_dir.'.zip', $new_dir))
{
return DataReturn('压缩包生成失败', -100);
}
// 生成成功删除目录
\base\FileUtil::UnlinkDir($new_dir);
// 开始下载
2021-05-06 11:13:09 +00:00
if(\base\FileUtil::DownloadFile($new_dir.'.zip', $config['name'].'_v'.$config['ver'].'.zip'))
2019-06-16 08:22:43 +00:00
{
@unlink($new_dir.'.zip');
} else {
return DataReturn('下载失败', -100);
}
}
2021-04-23 08:43:23 +00:00
/**
* 主题配置信息
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2021-04-22
* @desc description
* @param [string] $theme [主题标识]
*/
public static function ThemeConfig($theme)
{
// 获取配置信息
$config_file = ROOT.self::$html_path.$theme.DS.'config.json';
if(!file_exists($config_file))
{
return DataReturn('主题配置文件不存在', -1);
}
$config = json_decode(file_get_contents($config_file), true);
if(empty($config))
{
return DataReturn('主题配置信息有误', -1);
}
return DataReturn('success', 0, $config);
}
/**
* web主题更新信息
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2021-04-22
* @desc description
* @param [array] $params [输入参数]
*/
public static function ThemeUpgradeInfo($params = [])
{
if(!empty($params))
{
// 数据处理
$data = [];
foreach($params as $v)
{
if(!empty($v['name']) && !empty($v['ver']) && !empty($v['theme']) && !empty($v['author']))
{
$data[] = [
'plugins' => $v['theme'],
'name' => $v['name'],
'ver' => $v['ver'],
'author' => $v['author'],
];
}
}
if(!empty($data))
{
// 获取更新信息
$request_params = [
'plugins_type' => 'webtheme',
'plugins_data' => $data,
];
$res = StoreService::PluginsUpgradeInfo($request_params);
2021-11-09 14:54:59 +00:00
if(!empty($res['data']) && is_array($res['data']))
2021-04-23 08:43:23 +00:00
{
$res['data'] = array_column($res['data'], null, 'plugins');
}
return $res;
}
}
return DataReturn('无插件数据', 0);
}
2018-12-28 10:58:37 +00:00
}
?>