PHPCMS源码分析总结
一、背景
因为学习PHP的需要,对PHPCMS的源码进行了全面的分析。因为以前曾经用ASP做过一套内容管理系统,对模板引擎这一块有比较深入的了解,所以着重分析了模板这一部分。这里主要是针对思想的总结,而不是对代码的讲解。这里是针对PHPCMS2008版本进行分析。
二、目的
1. 深入学习PHP语言,熟悉PHP常用的函数的应用。熟悉和了解面向对象的开发。
2. 了解一个系统的整体框架,学习其中的优点。
3. 分析系统的模板引擎,和曾经做过的内容管理系统做对比,总结两者的优缺点。
4. 分析系统的缓存机制,因为以前很少接触这方面,有必要系统的学习和深入了解,对今后的系统优化作准备。
5. 学习权限体系,权限体系是整个框架的重要组成部分,可以吸取别人的长处。
三、整体框架
1. 主要目录
Include:包含目录,整个网站的公用函数、包含文件等都放在这里,十分重要
Languages:语言目录,所有的语言包都放在这里,一个子目录就是一个语言包
Data:缓存目录,里面对缓存文件进行了分类
Data/Cache:文本缓存目录,对数据库的数据进行了文本缓存,会经常用到
Data/Cache_template:模板目标文件目录,存放模板源文件编译的目标php文件
Data/Cache_page:静态缓存目录,动态文件的静态缓存页面
Data/datasource:数据库表和字段的说明文件
Templates:模板源文件目录,存放模板和标签的源文件
Admin:后台目录,存放后台相关的文件
/Admin/template:后台模板目录
Uploadfile:上传目录,存放上传的所有图片和文件
2. 主要文件
/admin.php:后台的入口页面
/index.php:首页的入口页面
/list.php:栏目页的入口页面
/show.php:最终页的入口页面
/include/cache.func.php:文本缓存的相关函数
/include/common.inc.php:动态页面的主包含文件,负责页面输出的主要工作,极为重要
/include/config.inc.php:配置文件,定义全局性的常量
/include/date.class.php:日期类
/include/db_mysql.class.php:连接mysql数据库的数据类
/include/dir.func.php:目录类,在生成静态页、创建缓存的时候会经常用到
/include/form.class.php:界面类,封装了一些生成界面的公共函数
/include/global.func.php:公用函数库,十分重要
/include/priv_group.class.php:会员组的权限类
/include/priv_role.class.php:角色的权限类
/include/template.func.php:模板相关函数库,在模板编译的时候需要用到
/include/upload.class.php:上传类,上传文件或者图片需要用到
3. 页面的输出过程
第一, 通过/admin.php的入口页面,根据不同的参数,包含不同的页面
第二, 后台的整体框架分为两部分,一部分是上边的头和菜单以及左边的菜单,另一部分是右边的操作区。通过jquery的load方法,只在操作区上加载各个页面的模板,实现局部刷新页面的效果,看样子像是框架,实际上是AJAX。
第三, 输出页面的准备工作是由/include/common.inc.php来完成的,而真正的输出页面的工作,是由template函数取出包含页面就可以了,比较简单。
第四, 这里主要介绍common.inc.php这个文件
首先,定义各个常数
其次,包含所有需要的文件,有包含文件、函数库和类文件,还有语言包
然后,判断是否开启了页面缓存,如果开启了,就输出缓存页面,具体的缓存机制稍后做详细分析
接着,用ob函数开辟一个缓存区,准备把输出的页面放入到缓存区,这里还判断了是否需要压缩页面。压缩页面的好处就是可以减少页面体积,提高浏览速度,但付出的代价就是服务器的性能。
开启数据库连接
判断是否开启了魔法函数,如果没有开启,需要用addslashes函数对GET、POST和Cookie进行非法字符的过滤,在用extract展开为变量
还需要对URL进行非法字符的判断,这些都是安全方面的考虑
如果开启了自动更新文本缓存,需要包含cache.func.php文件,然后更新缓存,这个选项最好是不要开启,否则会影响速度
获取文本缓存的内容,并展开为变量,然后unset文本缓存
如果是前台,需要判断刷新最小间隔时间
主要就是这么多步骤,这是访问所有php文件之前都必须做的准备工作,因为考虑得比较细,所以才会这么复杂。
4. 前台页面和后台页面输出过程的区别
后台页面输出明显比前台页面要复杂得多,主要是需要包含的页面和定义的常量要多很多,而且后台页面还需要判断角色的权限以及是否登录。
前台页面需要设置seo相关项目,内容页是写死的,其他页面都是通过后台的栏目设置,然后从文本缓存中读取出来的,而后台不用设置seo选项。
5. 关于数组的应用
在系统中大量运用了数组,特别是多维数组
首先,很多文本缓存都是用数组形式表现的
其次,很多字段也都是保存为数组的
再次,数组的运用非常广泛,比如查询出来的记录集,也被转成了数组,返回给页面,页面处理的就是数组,和数据库没有任何关系。
6. 面向对象的运用
封装了多个对象,这个是应该好好学习的
但是对数据类的封装比较简单,应该更加通用和抽象一点,比如把保存数据封装成一个方法,其他所有操作都调用这个方法,数据通过多维数组来传递。
四、模板引擎
1. 系统常量:系统自定义的常量,一般都是数组取文本缓存或者变量取Cookie
2. 标签:这里的标签实际上就是设置get函数的各个参数,包括获取数据的sql语句,对应的查询条件和自定义参数等,模板引擎的精华就在于此。get函数在编译成php文件的时候,会自动转换为tag函数
3. 模板:分为普通模板和标签模板,在标题上加以区分
4. 页面:该系统没有集中对页面进行管理,对页面没有一个明显清晰的概念。所有的模板都对应一个html页面,是模板源文件,然后再编译成php文件。
5. 页面的对应关系:是通过模型来对应页面的,模型就相当于一个模块,每个模块的前台页面模板不相同,比如新闻和产品。每个模型都有三种页面,栏目页、列表页和内容页。而栏目和模型是绑定的,这样每个栏目都有对应的模板。
6. 模板和标签的关系:模板是展示格式,标签是取数据。也就是说模板都是可见的,而标签都是和动态数据相关的,并没有明确的格式,只有和模板关联起来才会输出内容。
7. 好处
第一, 修改和保存模板都是通过文本文件,而不是通过数据库,可以大大提高速度,而且便于用ftp直接修改模板源文件。另外,还可以对模板文件分类,形成多套模板。
第二, 在模板中增加了逻辑语法,使得模板制作更加灵活简便
第三, 通过正则把模板源文件转换成符合PHP语法的动态页面,完全避免了字符替换中的复杂逻辑处理,把复杂业务都交给php文件来处理。
第四, 引入了风格,可以统一更换css
第五, 替换模板采用的是template标记,在编译的时候,会转换为include文件,就避免了模板的查找和替换。同时保证了页面的完整性,取代了框架的概念。
第六, 静态页的生成,都是通过入口动态页,把结果页面通过缓存取出来,再写入静态页面,节省了编译模板文件的步骤。
第七, 动态页还是静态页,是通过各个栏目来设置的,可以根据需要实现部分动态
第八, 标签的设置实现了可视化
第九, 样式表实现了统一设置,是通过文件路径参数化来实现,文件路径由皮肤路径和模块名组成,模块是一个比较好的概念,便于有效管理。
第十, 因为采用标准的php语法,数据库中的数据在模版中都是用字段数组的形式表现出来,替代了繁琐的标签设置。
8. 坏处
第一, 优 化选项没有集中管理,不利于优化人员的工作。特别是内容页的优化选项,是写在动态页面中的,如果要做调整,必须要更改程序文件,而且不能针对各个模板设置 不同的优化选项。可见,在设计框架时,根本就没有考虑内容页的优化,只是考虑了首页和各个栏目页的优化,这可能考虑到了内容页的优化大多数情况下不受重 视。
第二, 对页面没有一个清晰的概念,更没有管理页面的功能,都是以模板页面的形式出现。
第三, 模板和标签的概念混淆,模板调用标签,标签又引用模板,这可能会让人弄不明白。而且模板没有明确的分类,只是用标题区分了普通模板和标签模板。
第四, 可以实现页面预览效果,但如果有参数的话,需要输出参数后才能预览,这就比较麻烦,为什么不能实现参数的自动填充呢。
第五, 从一个页面要修改相关模板,必须要点击三次鼠标,一是不直观不方便,二是速度会比较慢,效率比较低。另外,从一个模板中,无法找到调用或者引用它的页面情况。
第六, 无法实时生成静态页,而且不能统一生成静态页,没有实现一键生成,在生成页面的时候没有显示进度条。
第七, 不能实现共享标签,如果只是查询参数不同,就必须重新增加一个标签。不如getinfo函数方便,可以根据具体情况随意调用。当然getinfo函数不够直观,虽然也有可视化界面。
9. 综述
综上所述,该系统的模板引擎在架构上来说还是很大气的,特别是充分利用了PHP语言的特点,把模板文件编译成PHP页面,大大简化了模板引擎。另一方面,由于架构上的限制,只能局限于PHP语法的转换,而无法在转换过程中作更多的工作,在提高速度和开发效率的时候,同时降低了维护的效率和易用性。
五、缓存机制
1. 文本缓存:就是把数据库中的数据,写到文本上,前提是这些数据是固定不变的或者是不经常更新的。在文本上表现的是数组形式,通过cache_read函数返回include文件,再赋值给数组,实现从文本取数据,省略了读取数据库的步骤,大大提高了速度。
2. 静态缓存:和IE的缓存差不多,都有一个缓存周期,在这个周期之内,可以访问静态缓存,不用访问动态页面,提高访问速度。
静态缓存的生成过程:在访问php页面的时候,如果有缓存页面,并且没有失效,就输出静态缓存,否则,开辟一个缓存区域,把php页面输出的内容,写入到缓存页面。该页面的目录和名称是把页面的php文件名称,包括参数,用md5函数加密后得到的字符串。
判断缓存文件是否失效,根据时间戳,生成缓存的时间戳写在缓存页面的开始,输出缓存页面,并不是简单的载入或者包含,而是把时间戳后面的内容echo出来。
3. 压缩功能:需要开启gzip扩展,压缩功能可以减小页面的尺寸,提高访问速度,但对服务器的压力很大,需要有较好的服务器。
4. 好处
第一, 网络访问的瓶颈在数据库的读取上,尽量减少对数据库的读取工作,是缓存的核心任务
第二, 静态缓存在大访问量的时候,速度会有较大的提高,如果访问量不大,最好关闭静态缓存。
六、权限体系
1. 权限的分配
首先,必须先设置会员,然后再设置管理员。会员有会员组,管理员有角色。
其次,说明栏目与模块的区别。栏目是针对前台,模块是针对后台的。栏目的权限分配可以分别针对会员组和角色,模块的权限分配只针对角色。
然后,会员组和角色的权限表是分开的。在登录的时候,会判断是前台还是后台,如果是前台,就取会员组表的权限,如果是后台,就取角色表的权限。
2. 权限的判断
首先,根据用户序号,从文本缓存中取出角色的序号
然后判断该角色是否有权限操作该模块
权限的判断很简单,并没有用权限编号来实现。这个跟系统架构有关,因为整个后台只有一个入口页面,所以通过传递参数的方式,可以实现模块名称,也就相当于模块编号的传递,可以实现统一判断用户的权限,而不必把权限号写在页面中,便于维护。
3. 优点
第一, 实现了权限判断的集中统一,便于维护
第二, 把前后台的权限分离开来,即栏目和模块区分开来,条理比较清晰
第三, 权限设置比较细,有一套完整的审核、编辑权限机制,是和工作流结合起来
4. 缺点
第一, 管理员和会员没有分离,要想设置管理员,必须设置会员,前后台还是没有完全分离。
第二, 设 置权限太麻烦,需要针对每个栏目或者模块进行设置,不知道这是不是和工作流结合有关。如果栏目或者模块多了,再加上管理员也多,设置起来会十分繁琐,特别 是人员流动频繁的网站,权限分配的可用性很低。角色和会员组没有发挥自身的功能,只是简单的分组,如果加上权限分配功能,对权限进行统一分配,会好很多。
第三, 用户登录后,只是一级权限做了屏蔽,但二级和三级权限是全部都显示出来,对用户来说是十分不友好的。
5. 综述
综上所述,系统的权限体系因为整体框架的限制,存在较大的局限性,较低的可用性,不是做得特别好,有待改进。