1. 程式人生 > >thinkcmf5更新模板代碼分析,解決模板配置json出錯導致數據庫保存的配置項內容丟失問題

thinkcmf5更新模板代碼分析,解決模板配置json出錯導致數據庫保存的配置項內容丟失問題

gets pat base flag find() 配置 sch 用戶自定義函數 ==

 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出錯導致數據庫保存的配置項內容丟失問題