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


     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)." ";
    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 "
    ".$tplFile."
    ";
                        $more     = $this->updateThemeConfigMore($configMore, $moreInDb);
                        //echo empty($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),
                            'config_more' => json_encode($configMore),
                            'description' => $config['description'],
                            'is_public'   => $isPublic,
                            'list_order'  => $listOrder
                        ]);
                         
                    }
                }
            }
  • 相关阅读:
    全排列和全组合实现
    (原)关于MEPG-2中的TS流数据格式学习
    linux的PAM认证和shadow文件中密码的加密方式
    vim 撤销 回退操作
    memcached解压报错gzip: stdin: not in gzip format tar: Child returned status 1 tar: Error is not recoverable: exiting now的解决方法
    Linux系统安全之pam后门安装使用详解
    漏洞预警:Linux内核9年高龄的“脏牛”0day漏洞
    linux软链接的创建、删除和更新
    关于“.bash_profile”和“.bashrc”区别的总结
    linux下批量杀死进程
  • 原文地址:https://www.cnblogs.com/djiz/p/7581189.html
Copyright © 2020-2023  润新知