private function updateThemeFiles($theme, $suffix = 'html')
{
$dir = 'themes/' . $theme;
$themeDir = $dir;
$tplFiles = [];
$root_dir_tpl_files = cmf_scan_dir("$dir/*.$suffix"); //默认情况下返回 模板目录(w0s目录)下的所有html文件名数组
foreach ($root_dir_tpl_files as $root_tpl_file) {
$root_tpl_file = "$dir/$root_tpl_file";
$configFile = preg_replace("/\.$suffix$/", '.json', $root_tpl_file); //获取当前$root_tpl_file对应json文件名 例如 index.json
$root_tpl_file_no_suffix = preg_replace("/\.$suffix$/", '', $root_tpl_file); //获取对应文件名无后缀
if (is_file($root_tpl_file) && file_exists_case($configFile)) { //当前$root_tpl_file(例如:index.html)是个文件,并且index.json存在
array_push($tplFiles, $root_tpl_file_no_suffix); //把文件名存起来,不包含后缀。例如:index
}
}
$subDirs = cmf_sub_dirs($dir); //子目录下文件,是不是只支持两级目录????
foreach ($subDirs as $dir) {
$subDirTplFiles = cmf_scan_dir("$dir/*.$suffix");
foreach ($subDirTplFiles as $tplFile) {
$tplFile = "$dir/$tplFile";
$configFile = preg_replace("/\.$suffix$/", '.json', $tplFile);
$tplFileNoSuffix = preg_replace("/\.$suffix$/", '', $tplFile);
if (is_file($tplFile) && file_exists_case($configFile)) {
array_push($tplFiles, $tplFileNoSuffix);
}
}
} foreach ($tplFiles as $tplFile) { //遍历所有文件json文件
$configFile = $tplFile . ".json";
$file = preg_replace('/^themes\/' . $theme . '\//', '', $tplFile);
$file = strtolower($file);
$config = json_decode(file_get_contents($configFile), true);
$findFile = Db::name('theme_file')->where(['theme' => $theme, 'file' => $file])->find();
$isPublic = empty($config['is_public']) ? 0 : 1;
$listOrder = empty($config['order']) ? 0 : floatval($config['order']);
$configMore = empty($config['more']) ? [] : $config['more'];
$more = $configMore; if (empty($findFile)) { //在数据表theme_file没有找到该模板 则插入
Db::name('theme_file')->insert([
'theme' => $theme,
'action' => $config['action'],
'file' => $file,
'name' => $config['name'],
'more' => json_encode($more),
'config_more' => json_encode($configMore),
'description' => $config['description'],
'is_public' => $isPublic,
'list_order' => $listOrder
]);
} else { // 更新文件
$moreInDb = json_decode($findFile['more'], true); //从数据库里读出来的more字段
$more = $this->updateThemeConfigMore($configMore, $moreInDb); //$configMore从index.json文件里读的json,$moreInDb从数据库里读的more字段的值
Db::name('theme_file')->where(['theme' => $theme, 'file' => $file])->update([
'theme' => $theme,
'action' => $config['action'],
'file' => $file,
'name' => $config['name'],
'more' => json_encode($more), //json文件里有并且从数据里取值以后,这里如果$configMore没有正确读取的话应该是返回了一个空值,没有保存成功
'config_more' => json_encode($configMore), //从index.json来的配置文件
'description' => $config['description'],
'is_public' => $isPublic,
'list_order' => $listOrder
]);
}
} // 检查安装过的模板文件是否已经删除
$files = Db::name('theme_file')->where(['theme' => $theme])->select(); foreach ($files as $themeFile) {
$tplFile = $themeDir . '/' . $themeFile['file'] . '.' . $suffix;
$tplFileConfigFile = $themeDir . '/' . $themeFile['file'] . '.json';
if (!is_file($tplFile) || !file_exists_case($tplFileConfigFile)) {
Db::name('theme_file')->where(['theme' => $theme, 'file' => $themeFile['file']])->delete();
}
}
}
/**
* 替代scan_dir的方法
* @param string $pattern 检索模式 搜索模式 *.txt,*.doc; (同glog方法)
* @param int $flags
* @param $pattern
* @return array
*/
function cmf_scan_dir($pattern, $flags = null)
{
$files = glob($pattern, $flags); //函数返回匹配指定模式的文件名或目录。该函数返回一个包含有匹配文件 / 目录的数组。如果出错返回 false。http://www.w3school.com.cn/php/func_filesystem_glob.asp
if (empty($files)) {
$files = [];
} else {
$files = array_map('basename', $files); //函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。 basename 函数返回路径中的文件名部分
} return $files; //指定规则的文件的文件名数组,在更新模板时,返回的是所有.html的文件名,带扩展名 http://www.w3school.com.cn/php/func_filesystem_basename.asp。
}
 private function updateThemeConfigMore($configMore, $moreInDb)
{

//echo empty($configMore);
// print_r($configMore); 
// return;

if (!empty($configMore['vars'])) {
foreach ($configMore['vars'] as $mVarName => $mVar) {
if (isset($moreInDb['vars'][$mVarName]['value']) && $mVar['type'] == $moreInDb['vars'][$mVarName]['type']) {
$configMore['vars'][$mVarName]['value'] = $moreInDb['vars'][$mVarName]['value']; //数据库里有这个vars,并且类型一样,则更新这个值到配置文件数组里。 if (isset($moreInDb['vars'][$mVarName]['valueText'])) {
$configMore['vars'][$mVarName]['valueText'] = $moreInDb['vars'][$mVarName]['valueText'];
}
}
}
} if (!empty($configMore['widgets'])) {
foreach ($configMore['widgets'] as $widgetName => $widget) { if (isset($moreInDb['widgets'][$widgetName]['title'])) {
$configMore['widgets'][$widgetName]['title'] = $moreInDb['widgets'][$widgetName]['title'];
} if (isset($moreInDb['widgets'][$widgetName]['display'])) {
$configMore['widgets'][$widgetName]['display'] = $moreInDb['widgets'][$widgetName]['display'];
} if (!empty($widget['vars'])) {
foreach ($widget['vars'] as $widgetVarName => $widgetVar) { if (isset($moreInDb['widgets'][$widgetName]['vars'][$widgetVarName]['value']) && $widgetVar['type'] == $moreInDb['widgets'][$widgetName]['vars'][$widgetVarName]['type']) {
$configMore['widgets'][$widgetName]['vars'][$widgetVarName]['value'] = $moreInDb['widgets'][$widgetName]['vars'][$widgetVarName]['value']; if (isset($moreInDb['widgets'][$widgetName]['vars'][$widgetVarName]['valueText'])) {
$configMore['widgets'][$widgetName]['vars'][$widgetVarName]['valueText'] = $moreInDb['widgets'][$widgetName]['vars'][$widgetVarName]['valueText'];
}
} }
} }
} return $configMore;
}

问题关键在函数  updateThemeConfigMore($configMore, $moreInDb);   如果json文件有语法错误,$configMore没有正确读取。可能造成配置丢失。

在函数updateThemeConfigMore开头加如下代码输出json生成的数组

echo empty($configMore)."\n";
print_r($configMore); 
return;

模板更新,当json文件有语法错误(如少一个逗号)时,$configMore的值是空数组,empty($configMore)值返回1。

themes/w0s/portal/index
1 Array
(
)

解决方案 updateThemeFiles函数里增加对json转换结果的判断,转换成功再更新数据库。

private function updateThemeFiles($theme, $suffix = 'html')
{
$dir = 'themes/' . $theme;
$themeDir = $dir;
$tplFiles = [];
$root_dir_tpl_files = cmf_scan_dir("$dir/*.$suffix");
foreach ($root_dir_tpl_files as $root_tpl_file) {
$root_tpl_file = "$dir/$root_tpl_file";
$configFile = preg_replace("/\.$suffix$/", '.json', $root_tpl_file);
$root_tpl_file_no_suffix = preg_replace("/\.$suffix$/", '', $root_tpl_file);
if (is_file($root_tpl_file) && file_exists_case($configFile)) {
array_push($tplFiles, $root_tpl_file_no_suffix); }
}
$subDirs = cmf_sub_dirs($dir);
foreach ($subDirs as $dir) {
$subDirTplFiles = cmf_scan_dir("$dir/*.$suffix");
foreach ($subDirTplFiles as $tplFile) {
$tplFile = "$dir/$tplFile";
$configFile = preg_replace("/\.$suffix$/", '.json', $tplFile);
$tplFileNoSuffix = preg_replace("/\.$suffix$/", '', $tplFile);
if (is_file($tplFile) && file_exists_case($configFile)) {
array_push($tplFiles, $tplFileNoSuffix);
}
}
} foreach ($tplFiles as $tplFile) {
$configFile = $tplFile . ".json";
$file = preg_replace('/^themes\/' . $theme . '\//', '', $tplFile);
$file = strtolower($file);
$config = json_decode(file_get_contents($configFile), true);
$findFile = Db::name('theme_file')->where(['theme' => $theme, 'file' => $file])->find();
$isPublic = empty($config['is_public']) ? 0 : 1;
$listOrder = empty($config['order']) ? 0 : floatval($config['order']);
$configMore = empty($config['more']) ? [] : $config['more'];
$more = $configMore; //json没有转换成功就不更新数据库
if(!empty($config)){
if (empty($findFile)) {
Db::name('theme_file')->insert([
'theme' => $theme,
'action' => $config['action'],
'file' => $file,
'name' => $config['name'],
'more' => json_encode($more),
'config_more' => json_encode($configMore),
'description' => $config['description'],
'is_public' => $isPublic,
'list_order' => $listOrder
]);
} else { // 更新文件
$moreInDb = json_decode($findFile['more'], true);
//echo "\n".$tplFile."\n";
$more = $this->updateThemeConfigMore($configMore, $moreInDb);
//echo empty($more)."\n"; Db::name('theme_file')->where(['theme' => $theme, 'file' => $file])->update([
'theme' => $theme,
'action' => $config['action'],
'file' => $file,
'name' => $config['name'],
'more' => json_encode($more),
'config_more' => json_encode($configMore),
'description' => $config['description'],
'is_public' => $isPublic,
'list_order' => $listOrder
]); }
}
}

thinkcmf5更新模板代码分析,解决模板配置json出错导致数据库保存的配置项内容丢失问题的更多相关文章

  1. 使用 c++ 模板显示实例化解决模板函数声明与实现分离的问题

    问题背景 开始正文之前,做一些背景铺垫,方便读者了解我的工程需求.我的项目是一个客户端消息分发中心,在连接上消息后台后,后台会不定时的给我推送一些消息,我再将它们转发给本机的其它桌面产品去做显示.后台 ...

  2. kafkaStream解析json出错导致程序中断的解决方法

    出错在 KStreamFlatMapValues 方法执行时,由于json异常数据无法解析,结果生成的值为null,报错信息如下: 2018-04-18 19:21:04,776 ERROR [app ...

  3. kafka没配置好,导致服务器重启之后,topic丢失,topic里面的消息也丢失

    转,原文:https://blog.csdn.net/zfszhangyuan/article/details/53389916 ----------------------------------- ...

  4. Linux内核中的GPIO系统之(3):pin controller driver代码分析

    一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...

  5. Linux内核中的GPIO系统之(3):pin controller driver代码分析--devm_kzalloc使用【转】

    转自:http://www.wowotech.net/linux_kenrel/pin-controller-driver.html 一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道 ...

  6. 使用SonarCloud对.NET Core项目进行静态代码分析

    本文将介绍如何使用SonarCloud进行.NET Core项目的静态代码分析.SonarCloud是SonarQube提供的基于云的版本,特别针对于开源项目是免费的. 首先,在sonarcloud. ...

  7. flask模板结构组织(局部模板、宏、模板继承)

    模板结构组织 除了使用函数.过滤器等工具控制模板的输出外,jinja2还提供了一些工具来在宏观上组织模板内容. 局部模板 在Web程序中,我们通常会为每一类页面编写一个独立的模板.比如主页模板.用户资 ...

  8. Android Studio 配置快速生成模板代码

    前言 Android studio 有提供快速生成模板代码的功能,其实这个功能也可以自定义配置.此篇博客将讲解如何使用此功能 进入Settings 选择 Editor > Live Templa ...

  9. LibOpenCM3(二) 项目模板 Makefile分析

    目录 LibOpenCM3(一) Linux下命令行开发环境配置 LibOpenCM3(二) 项目模板 Makefile分析 LibOpenCM3 项目模板 项目模板地址: https://githu ...

随机推荐

  1. Python-12-简单推导

    列表推导:从其他列表创建列表 >>> [x * x for x in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 下面实现只打印能 ...

  2. ES6新特性使用小结(四)

    十一.Proxy .Reflect ①.Proxy 的概念和常用方法 { let obj = { //1.定义原始数据对象 对用户不可见 time: '2017-09-20', name: 'net' ...

  3. Codeforces Round #377 (Div. 2) D. Exams 贪心 + 简单模拟

    http://codeforces.com/contest/732/problem/D 这题我发现很多人用二分答案,但是是不用的. 我们统计一个数值all表示要准备考试的所有日子和.+m(这些时间用来 ...

  4. 传智播客C++

    轻松入门实战应用传智播客C++学院就业班第一阶段C提高课程 传智播客C提高讲义 传智扫地僧 1程序内存模型 1.1就业班引言 1.1.1问题引出 企业需要能干活的人  C学到什么程度可以找工作  ...

  5. tomcat调优方案Maximum number of threads (200) created for connector with address null and port 8091

    1.tomcat6大并发出现:INFO: Maximum number of threads (200) created for connector with address null and por ...

  6. form-data、x-www-form-urlencoded、raw、binary的区别

    1.form-data: 就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开.既可以上传键值对,也可以上传文件.当上传的字段是文件时 ...

  7. HTML5:使用postMessage实现Ajax跨域请求

    HTML5:使用postMessage实现Ajax跨域请求 由于同源策略的限制,Javascript存在跨域通信的问题,典型的跨域问题有iframe与父级的通信等. 常规的几种解决方法: (1) do ...

  8. BZOJ4939: [Ynoi2016]掉进兔子洞(莫队 bitset)

    题意 题目链接 一个长为 n 的序列 a. 有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一个删,不是把等于 ...

  9. PHP变量、数据类型、字符串、运算符、条件语句、循环语句、数组、函数

    PHP 简介: php :是一门动态交互的计算机语言  静态交互 html  css  js 但凡是动态交互的 都需要服务器. php都是以.php结尾的文件 Html文件里不能写php代码,但是ph ...

  10. mui实现图片更换(暂未上传)

    页面中有默认的图片,触发type为file的input时,更换图片,这个是mui移动端的项目,算了,不多说,开码 首先,先在html页面中设置样式,样式我就不给了,贴个布局 <div class ...