dedecms核心类源码分析

  最近公司一个cms类型的项目,时间紧任务重。经过快速的决策后,选择了dedecms开发1.0版本,满足基本需求。以前从来没有接触过这个系统,而且此系统文档是相当的不全。所以分析源代码是最好的方式。学习一个系统,首要的是搞懂它的数据引擎、模板引擎。dedetag.class.php 这个文件就是核心底层模板解析引擎,其它的引擎都是在这个基础上增加了自己的函数而已。

一、dedetag.class.php

 1.DedeTag :最后存储的CTags的结构类,提供一些读取CTags属性的方法。(这个很重要)
    2.DedeAttribute : 最后存储的CTags->attr 的属性结构类(count,Items)
    3.DedeAttributeParse: 属性解析器,解析提供属性结构到CTags变量。
    4.DedeTagParse :核心解析器       

复制代码

 1        1.LoadTemplate 载入模板。
 2             1. while($line = fgets($fp,1024)) //line 379循环读取文件赋值到变量 $this->SourceString .= $line;
 3             2. if($this->LoadCache($filename))//line 384在有缓存的情况,读取缓存文件到 CTags
 4             3.  $this->ParseTemplet();//line 390 没有缓存则调用模板解析方法
 5         2.ParseTemplet 解析模板
 6             1.循环遍历,按正则匹配每个标签的位子和属性,并保存到 CTags
 7             2. $this->SaveCache(); //line 952 ,如果开启缓存配置则保存到缓存文件
 8         3.GetResult 输出模板
 9             1. $this->AssignSysTag();// line 738 处理特殊标记(global,include,foreach,var,runphp)(global模板,能处理模板上的函数,和10步一样)      
10         4.AssignSysTag  处理特殊标记(global,include,foreach,var,runphp)(global模板,能处理模板上的函数,和10步一样)
11         5.Assign         封装模板的类(arclist/channel/memeberlist.....)和字段的解析是channelunit.helper.php中MakeOneTag函数在处理,
12             $dtp->Assign($tagid,$funcname($ctag,$refObj)); // line 558 调动地底层模板解析引擎的赋值函数为便签赋值。            

复制代码

二、arc.partview.class.php 分析

复制代码

 1     index.php调用arc.partview.class.php
 2     1.$this->dtp = new DedeTagParse();//line 47 初始化底层模板解析引擎
 3     2.$this->SetTemplet();//line 134 读取要解析的模板 
 4     3.$this->dtp->LoadTemplet($temp); //line 142 实际调用的是底层模板解析引擎 
 5     4.$this->ParseTemplet(); //line 149 封装的解析模板方法
 6     5.MakeOneTag($this->dtp,$this); //line 224 这个函数放在 channelunit.func.php 文件中,
 7     6.helper('channelunit');// line 29 调用helper工具加载对应的函数。channelunit.helper.php
 8     7.if($tagname=='field' && $parfield=='Y') //line 515 解析field 模板
 9     8.$funcname = 'lib_'.$tagname; //line 557 加载对应的封装模板的类(arclist/channel/memeberlist.....)
10     9.$dtp->Assign($tagid,$funcname($ctag,$refObj)); // line 558 调动地底层模板解析引擎的赋值函数为便签赋值。
11    10.$this->$dtp->EvalFunc($fieldvalue,$functionname,&$refObj); //line 965 动地底层模板解析引擎处理某字段的函数(模板中直接使用函数最终也是调用的此方法加载对应的函数返回值)
12    11.$this->dtp->GetResult();//line 169 调动地底层模板解析引擎的输出方法
13    12.$this->dtp->AssignSysTag(); //line 738  调动地底层模板解析引擎处理特殊标记(global,include,foreach,var,runphp)(global模板,能处理模板上的函数,和10步一样)
14    13.$this->dtp->CTags[$i]->TagValue = $str; 每一次解析模板赋值都会修改CTags的TagValue
15    
16    总结:封面模板解析类是对 dedetag.class.php 的封装。加入了一些自己的处理逻辑

复制代码

三、写自己的模板解析

      

    

复制代码

  1 TypeID = $typeid;
 29         $this->dsql = $GLOBALS['dsql'];
 30         $this->dtp = new DedeTagParse();
 31         $this->dtp->SetNameSpace("dede", "{", "}");
 32         $this->dtp->SetRefObj($this);
 33         $this->ftp = &$ftp;
 34         $this->remoteDir = '';
 35         //加载模板->解析模板
 36         $this->dtp->LoadTemplet(DEDETEMPLATE ."/default/test.htm");
 37 
 38         //字段,通过{dede:filed.myname}访问到。在display时,由$this->dtp->AssignSysTag()处理
 39         //如果需要面包屑导航等信息,则要new TypeLink,原理也是往Fields中在赋值
 40         if ($needtypelink) {
 41             $this->TypeLink = new TypeLink($typeid);
 42             if (is_array($this->TypeLink->TypeInfos)) {
 43                 foreach ($this->TypeLink->TypeInfos as $k=>$v) {
 44                     if (preg_match("/[^0-9]/", $k)) {
 45                         $this->Fields[$k] = $v;
 46                     }
 47                 }
 48             }
 49             $_sys_globals['curfile'] = 'partview';
 50             $_sys_globals['typename'] = $this->Fields['typename'];
 51 
 52             //设置环境变量
 53             SetSysEnv($this->TypeID, $this->Fields['typename'], 0, '', 'partview');
 54             $this->Fields['position'] = $this->TypeLink->GetPositionLink(true);
 55             $this->Fields['title'] = $this->TypeLink->GetPositionLink(false);
 56         }
 57         $this->Fields['myname']="mian_wu";
 58         //全局变量,可以通过{dede:globel.testlist}访问到。在display时,由$this->dtp->AssignSysTag()处理
 59         $GLOBALS['testlist']=array(1,2,3,4,5);
 60        
 61 
 62         //解析框架自定义模板,arclist/channel/memeberlist.....
 63         MakeOneTag($this->dtp, $this);
 64         //解析自己定义模板,沒有自定义则此代码不需要。
 65         foreach ($this->dtp->CTags as $tid => $ctag) {
 66             if ($ctag->GetName()=="myfield") {
 67                 //自定义单标签
 68                 //$this->assgin() //去解析自定义模板
 69                 $this->dtp->Assign($tid, $this->Fields[$ctag->GetAtt('name')]);
 70             } elseif ($ctag->GetName()=="mytag") {
 71                 //自定义复合标签
 72                 //自定义模板解析的两种方式
 73                 //1.可以写在taglib/tagName.lib.php的形式,模板会自动加载并解析。
 74                 //2.直接在CTags里面通过名字匹配到id,并assin进入值。
 75                 $this->dtp->Assign($tid, $this->Mytag($ctag->GetInnerText()));
 76             }
 77         }
 78     }
 79     public function Mytag($innertext)
 80     {
 81         //重新初始化底层解析模板。
 82         $dtp2 = new DedeTagParse();
 83         $dtp2->SetNameSpace('field', '[', ']');
 84         $dtp2->LoadSource($innertext);
 85         foreach ($dtp2->CTags as $k=>$ctag) {
 86             if ($ctag->GetName()=='myname') {
 87                 //此处赋的值,自行处理
 88                 $dtp2->Assign($k, "mian_wu");
 89             }
 90         }
 91         return $dtp2->GetResult();
 92     }
 93     public function Display()
 94     {
 95         //底层调用了$this->dtp->AssignSysTag();(global,include,foreach,var,runphp)
 96         $this->dtp->Display();
 97     }
 98 }
 99 
100 $a=new TestView(2);
101 $a->Display();

复制代码

 

    

复制代码

 1 
 2 
 3     
 4     
 5     
 6     {dede:global.cfg_webname/}
 7 
 8 
 9     {dede:foreach array="testlist"}
10      [field:key /]- [field:value /]
11      {/dede:foreach}
12 
13      
14 {dede:arclist limit='0,4' flag="p"} 15 16 {/dede:arclist}
17
18 {dede:field.myname /} 19 {dede:mytag} 20 [field:myname/] 21 {/dede:mytag} 22 23

复制代码

测试页面

 

 四、数据库操作分析

  

复制代码

 1    common.inc.php 核心类分析
 2     1.定义全局变量
 3     2.过滤请求参数
 4     3.加载数据库配置 require_once(DEDEDATA.'/common.inc.php');//line 152
 5     4.设置模板目录变量
 6     5.分页参数的设置
 7     6.自动加载类库处理
 8     7.引入数据库类
 9     8.全局常用函数 require_once(DEDEINC.'/common.func.php'); //在line 368,做了兼容处理,扩展的函数可以直接写在extend.func.php中。
11     9.路由处理,请求分发
12     10.载入小助手配置
13   dedesqli.class.php 
        

        $sql="xxxx";

        $dsql->Execute('name', $sql);

        while ($row = $dsql->GetObject('name')) {

         $arr[] = $row;

        }

14     1.$dsql = $dsqli = $db = new DedeSqli(FALSE);  //line 21 在工程所有文件中均不需要单独初始化这个类,可直接用 $dsql 或 $db 进行操作
15     2.SetQuery($sql) :会自动把SQL语句里的#@__替换为$this->dbPrefix(在配置文件中为$cfg_dbprefix)。并设置$this->queryString
16     3.Execute($id="me", $sql='') //如果sql不为空,内部会调用SetQuery,替换前缀。
18       $this->result[$id] = mysqli_query($this->linkID, $this->queryString); //line 315 执行sql返回执行结果。
19     4.GetOne($sql='',$acctype=MYSQLI_ASSOC) 
20        if(!preg_match("/LIMIT/i",$sql)) $this->SetQuery(preg_replace("/[,;]$/i", '', trim($sql))." LIMIT 0,1;");//line 351        //内部通过正则加上了limit 0,1
21        $this->Execute("one"); //line 354 调用Execute
22     5.GetArray和GetObject

function GetObject($id="me")

{

if($this->result[$id]===0)

{

return FALSE;

}

else

{

return mysqli_fetch_object($this->result[$id]);

}

}

23     6.ExecuteNoneQuery($sql='')执行一个不返回结果的SQL语句,如update,delete,insert等

复制代码

  五、总结

    dedecms 就两个核心类 dedetag.class.php、common.inc.php。一行行读源码,就可以知道它得工作原理。二次开发时,需要哪部分就找到对应的源码进行分析。其它的就应该没什么困难了。

  

标签: dedecms

//包含连接数据库的公共文件
require_once("./conn.php");

//开启SESSION会话
session_start();
//判断用户是否登录
if(empty($_SESSION['username']))
{
    //如果用户没有登录,则直接跳转到login.php
    header("location:./login.php"); 
    die();
}

//判断表单的来源是否合法
if(isset($_POST['token']) && $_POST['token']==$_SESSION['token'])
{
    //**********************上传图片*******************************
    //(1)判断上传图片是否有错误发生
    if($_FILES['uploadFile']['error']!=0)
    {
        echo "

上传图片有错误发生!

";
        header("refresh:3;url=./upload.php");
        die();
    }

    //(2)判断上传文件内容类型是不是图片
    $arr1 = array("image/jpeg","image/png","image/gif");
    //创建finfo的资源:获取文件内容类型,与扩展名无关
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    //获取文件内容的原始类型,不会随着扩展名改名而改变
    $mime = finfo_file($finfo,$_FILES['uploadFile']['tmp_name']);
    if(!in_array($mime,$arr1))
    {
        echo "

上传的必须是图像!

";
        header("refresh:3;url=./upload.php");
        die();        
    }

    //(3)判断上传的文件扩展名是不是图片
    $arr2 = array("jpg","gif","png");
    $ext  = pathinfo($_FILES['uploadFile']['name'],PATHINFO_EXTENSION); //文件扩展名
    if(!in_array($ext,$arr2))
    {
        echo "

上传的必须是图像!

";
        header("refresh:3;url=./upload.php");
        die();        
    }

    //(4)移动图片到 images目录中
    $tmp_name = $_FILES['uploadFile']['tmp_name'];
    $dst_name = "./images/".uniqid().".".$ext;
    move_uploaded_file($tmp_name,$dst_name);

    //***********************将表单提交数据保存到数据库****************************
    //(1)获取表单提交数据
    $title    = $_POST['title'];
    $intro     = $_POST['intro'];
    $imgsrc = $dst_name; //将图片路径保存到数据库
    $addate = time();

    //(2)判断记录是否添加成功
    $sql = "INSERT INTO photos VALUES(null,'$title','$imgsrc','$intro',0,$addate)";
    if(mysqli_query($link, $sql))
    {
        echo "

上传照片成功!

";
        header("refresh:3;url=./index.php");
        die();                
    }
}else
{
    //直接跳转到index.php页面
    header("location:./index.php");
}

你可能感兴趣的:(SEO,PHP)