第一章 Drupal 是如何工作的

本章将主要对Drupal的概貌进行介绍。关于系统是如何工作的那些细节,将留待后面的章节再讲解。此处,我们首先会介绍Drupal运行在什么样的技术堆栈(technology stack)上,还有Drupal的文件系统结构,最后是Drupal所使用的各种概念型术语,比如节点、钩子、区块和主题等。

第一节 什么是Drupal?

Drupal是用来建立网站的工具。它是一个高度模块化,开源的Web内容管理框架,同时它还专注于协作式的开发。它具有良好的扩展性,而且兼 容标准,同时还致力于清洁的代码和脚步递进式开发。Drupal内嵌了基础的核心功能,同时还能使用第三方开发的附加功能。可以说Drupal生来就是为 定制做准备的,但定制开发是由覆盖核心功能或是通过添加新模块来完成的,而非由修改核心模块代码来实现。Drupal的设计也成功的将内容管理与内容展现 分离开来。
 
Drupal可以被用来创建一个互联网上的门户网站;一个个人的,部门的,或是公司的网站;一个电子商务网站;一个资源目录;一个在线报纸;一个图片库;一个内网应用。这里只不过提了很少的几种可能性,Drupal甚至可以被用来教授远程在线课程(类似于LMS)。
 
有一支全职的安全团队正在努力通过应对各种安全问题和发布安全补丁包来使得Drupal变得更加安全。一个非盈利性的组织Drupal Association通过改进Drupal.org的网络设施来支持Drupal,同时它还组织了许多Drupal大会和聚会。并且,一个日益繁荣的 Drupal社区,一群网管们,网页设计者还有开发者们都在不停的贡献着自己的力量。参见http://drupal.orghttp://groups.drupal.org

 

第二节 技术堆栈

 
Drupal的设计目标包括了两点,在便宜的互联网主机租用提供商的主机上运行良好,以及,能够分布式的运行在大规模分布式网站上。前者意味着使用最流行和最被广泛接受的技术,后者,则意味着谨慎的,优秀的编码。Drupal的技术堆栈如图 1-1 所示
 
在这个技术堆栈中,操作系统的位置很低,也就是说Drupal并不是很关心你使用了什么操作系统,只要它能支持PHP就行。
 
Drupal最为广泛使用的Web服务器是Apache,但是其它服务器Drupal也支持,包括微软的IIS。由于DrupalApache之间悠长的历史,Drupal自带了.htaccess文件来为Drupal的安装提供安全保证。Clean URL功能也就是那些不带有问号、&号或其它奇怪字符的URL – 是由Apachemod_rewrite模块来提供的。这点尤其重要,因为当从其它CMS系统或是静态文件移植内容时,内容的URL地址不应该被改变,按照Tim Berners Lee(http://www.w3.org/Provider/Style/URI)的说法,不改变URI的做法是非常酷的。Clean URLs这种功能在其它Web服务器上也是允许存在的,只要使用了对应Web服务器的URL重写功能即可。
 
Drupal堆栈中的下一层,也就是数据库层,Drupal提供了轻量级的数据库抽象层。该层提供了一种公用SQL查询方式,可实现在无需重构任何业务代码的情况下使用不同厂商的数据库。这一点已经在MySQLPostgreSQL上被广泛测试,但是对于Microsoft SQL ServerOracle的支持还正在开发中。
 
Drupal是用PHP写的。因为PHP是一门很容易上手的语言,所以有很多PHP的程序,都是由新手写的。这些新手开发的程序中的代码质量,带给了PHP很不好的名声。然而事实是,PHP也是可以写出高质量代码的。所有的Drupal内核代码都遵守了严格的编程规范(http://drupal.org/nodes/318) 并且接受了开源软件流程非常彻底的审查。对Drupal来说,PHP的低学习曲线意味着为软件贡献者设置了很低的进入门槛,但审查流程确保了门槛低的同时不会牺牲最终产品的质量。同时从Drupal社区中收到的反馈又能帮助初学者们提高来改进他们的技巧。

第三节 Core 核心

Drupal的核心代码包括了处理用户请求时的完整流程,Drupal常用功能函数库,还有提供Drupal基本功能的模块代码,比如用户管理,分类(taxonomy),还有显示模板,参考下图所示:
 

第四节 管理界面

Drupal的管理界面是与它的整个网站坚密结合的,默认情况下,它们共同使用同一种主题。第一个用户,也就是user 1,是网站的超级用户,拥有至高无上的权限。使用user 1登录后,在你的User区块中(相关内容请参看“区块”章节),将会看到一个进入管理界面的链接。点击后,你就进入了Drupal的管理界面中。每个用户的User区块都会包含不同的链接,这是由用户自身的权限级别所决定的。

第五节 模块

Drupal是一个真正意义上的模块化的框架。它所有的功能,都包括在模块中,并且可以被启动或禁用(有些核心必须模块是无法被禁用的)。为一个网站添加功能,是可以通过启用新的模块来实现的,通常这些模块都已由Drupal开源社区的广大成员提供好了。当然,你也可以开发自己的模块。如此一来,在网站本身不需要某些功能时,就可以将它们禁用,使网站“瘦身”,或是在需要额外的功能时,可以按需任意添加。参见下图:
不管是添加新的诸如菜谱,博客,或文件等内容类型(Content types),还是添加如邮件提醒,点对点信息发布,RSS聚合等功能,它们都是由添加模块来实现的。Drupal使用了“控制反转”的设计模式,也就是让框架本身在适当时机去调用模块提供的功能。这种调用机制,在Drupal中,被称为钩子(Hook)

第六节 钩子

钩子可以被看作是Drupal的内部事件,它们也被叫做“回调函数”。这里需要注意的是,由于它们是按照函数命名规范来构建的,而非真正的注册了一个监听器listener,所以它们不算真正意义上的“回调”。
 
设想,一个用户登录了你的Drupal网站。在用户登录的时候,Drupal会调用hook_user这个钩子。这也就意味着,所有函数,只要是按照了“模块名称_钩子名称”这样的命名规范进行命名的,都会被调用。例如,comment_user()这个函数位于comment模块中,locale_user()这个函数则位于locale模块中,node_user()处于node模块中,它们会统统的被调用。事实上所有实现了这个钩子的模块都会被调用。如果你想写一个自己定制的模块,比如叫spammy.module,并且包括了一个函数叫spammy_user(),这个函数的功能是给用户发一封email。这个spammy_user()方法同样会在用户登录时被调用,并且那个不幸的用户在每次登录时都会收到一封邮件。
 
Drupal中,要想修改或覆盖Drupal的核心功能,最常见的方式就是在模块中实现相应的钩子。
 
Tip: 想了解更多关于Hooks的内容,请参见在线文档:http://api.drupal.org/api/6 。在Components of Drupal下,点击“Module system(Drupal hooks)”。

 

第七节 主题

当创建一个网页发往浏览器时,通常有两件事需要考虑:如何组装数据和如何为数据添上WEB标签以便在浏览器中显示。在Drupal中,主题层Theme layer负责生成发往浏览器的HTML(或是JSON,XML)Drupal能使用多种流行的模板技术,比如SmartyTemplate Attribute Language for PHP(PHPTAL),还有PHPTemplate
 
很重要的一点是,Drupal鼓励内容与表示层的分离。
 
Drupal允许多种方法来定制和覆盖网站的外观。最简单的方法是使用CSS来覆盖Drupal内置的classesIDs。然而,如果你希望更进一步,完全定制真正的HTML输出内容,你会发现这其实也很简单。Drupal的模板方件是由标准HTMLPHP文件组成。页面上每一动态的部分(比如一个区块,或是一个导航条breakcrumb trail)都可以通过简单的声明一个函数来对其进行覆盖,当然前提是该函数必须符合一定的命令规范。只要这样,Drupal就会使用你的方法来创建页面内容。

第八节 节点

Drupal中的各种内容类型是由一个基础的类型继承而来的,这个基础类型,就叫节点(node)。不管它是一个博客文章,还是一个菜谱,甚至于是一个项目中的任务,其所使用的底层数据结构都完全一样。如此架构的天才之处,在于它良好的扩展性。模块开发者可以添加新的功能,比如评分,评论,文件附件,地理信息等等,而且无须考虑节点类型是博客,菜谱还是别的什么。网站管理员然后将它们混合,并按照内容类型来映射各项功能。例如,管理员可能选择起用对博客的评论功能,但不起用对菜谱的评论功能,又或者起用对项目任务的文件上传功能。
 
节点还包含一组基本的行为属性,这些属性会被所有的内容类型所继承。任意一个节点,都能被显示于网站首页,被发布或是取消发布,甚至是被搜索。正是由于这样统一的架构,管理界面才能提供对于节点的批量编辑功能。

 

第九节 区块block

区块是网页中一个小区域,它的内容可以由管理员起用或是禁用。例如,一个区块可以显示你的网站中当前在线用户的总数。又或许,你会有一个区块,它包含了关于你的网站中最为流行的内容的链接,或者是网站将要进行的活动。区块经常被放在模板的侧边栏,顶栏或是页脚中。区块可以被设置为显示某一类型的几个节点,还可以设置只在首页显示该区块,或者是按其它条件进行显示。
 
通常,区块用来显示为当前用户所特定的信息。例如,User这个区块通常包含了当前用户所能够访问的管理页面链接,比如“My account”页面。区块能显示的区域是在网站的主题中预先定义的。区块的位置和可见性都可以在后台管理界面中进行管理。

 

第十节 文件结构

理解Drupal的默认文件系统结构可以教给你很多重要的技巧。比如,在哪里放置下载的新的模块和主题,或是如何安装不同配置的Drupal。默认的Drupal安装有下面的文件结构:
以下是对上图目录结构中所包含的各个元素的详细说明:
 
Includes目录中包含了Drupal所使用的一些通用函数库。
 
Misc目录中存储了Javascript脚本和各式图标、图片,在Drupal的默认安装中会用到它们。
 
Modules目录中包括了Drupal的核心模块,都分别在各自的目录内。比较好的做法是永远不去修改这个目录中的任何东西(或者说,除了Profilessites目录之外所有的目录,都不应该被修改)。用户添加的新模块,应该被放置于sites目录中。
 
Profiles目录存放着某个网站的不同的Drupal安装描述文件。如果除了默认安装外,这个目录中还有别的安装描述文件,Drupal会请示用户希望使用哪一个安装描述文件来安装Drupal。一个安装描述文件的主要作用是来自动的启用某些核心和第三方模块。比如说,如果使用了某个e-commerce安装描述文件,就可以自动的装网站设置成为一个电子商务平台。
 
Scripts目录中包含了一些脚本用来检查语法,清理代码,从命令行运行Drupal或是一些使用CRON的特殊的例子。这个目录在Drupal处理用户HTTP请求周期中并不会被用到;它们都是shellPerl的脚本。
 
Sites目录中存放着你对于Drupal的所有修改和定制,这包括系统设置、模块和主题。当你向Drupal中添加第三方模块或是你自己开发的模块时,只需将模块放到sites/all/modules目录中。这样就使得你对于当前网站的所有定制集中在一个目录下。在sites目录下是一个名为default的子目录,其中存放了默认的系统配置文件default.settings.phpDrupal的安装程序不会改动这些原始默认设置,而是会根据你所提供的配置信息,重新创建一个名为settings.php的文件,并将其置放于该目录下。通常来说,网站的创建者,会创建一个以网站URL为名的目录,这样一来,你最终的配置文件很有可能就会是sites/www.example.com/settings.php
 
默认情况下Drupal并不会创建Sites/default/files这个目录,但的确需要它来存储所有上传到你的网站上的文件。比如用户可能会上传一个定制的logo,或是个人头像或是一些和网站相关的视频。Files这个目录,需要Web服务器必须有读和写的权限才能正常使用。Drupal安装程序会自动检查该目录的读写权限,然后创建它。
 
Theme目录包含了模板引擎和一些默认的主题。用户所下载或自己创建的主题不应该被放在这,它们应该放在sites/all/themes
 
Cron.php是用来执行定时任务的,比如定时维护,备份数据库或是计算一些统计信息等。
 
Index.phpDrupal处理用户请求时的主要入口。
 
Install.phpDrupal安装程序的主要入口。
 
Update.php会在Drupal版本更新后,更新相应的数据库表。
 
Xmlrpc.php接收XML-RPC请求,如果不想使用XML-RPC功能,那就完全可以将其删除。
 
Robots.txt里面包含了一些默认的设置,用来保证搜索引擎在爬取网站时,可以避开一些关键内容。
 
还有一些没有列在这里的文件,都是属于文档性质:
 

第十一节 接受一个Web请求

从概念上了解一下Drupal在收到一个Web请求后都做了哪些事,是对学习Drupal非常有帮助的。这一小节会带领读者快速了解一下这一过程。如果你希望自己来跟踪调试这整个过程,那么请使用一个好的调试工具,并且从Index.php开始,因为Drupal的大部分请求都是被这个文件所接收的。本小节中所讲述的生成一个简单页面的过程,看起来似乎有些复杂,但这个过程中的每一步,都是相当灵活的。
 
Web服务器的角色
Drupal跑在一个web服务器之上,比如Apache。如果Web服务器尊循Drupal.htaccess文件,那么某些PHP设置就会被初始化而且URL会被检查。几乎所有对Drupal的访问,都要通过index.php文件。比如,当你调用http://example.com/foo/bar时,会经历以下步骤:
1.       定于在Drupal.htaccess文件中的Mod_rewrite规则,会将请求的URL进行切分,把基础路径取出,在我们的例子中,也就是foo/bar
2.       这个路径会被赋值给查询变量q
3.       于是,最终的URL变为http://example.com/index.php?q=foo/bar
4.       Drupalfoo/bar当成内部Drupal路径,并开始运行index.php进行处理。
 
由于这样的处理流程,所以Drupal认为,http://example.com/index.php?q=foo/barhttp://example.com/foo/bar实际上是同样的链接。因为从内部看来,两者的路径实际上是一样的。这也就使得Drupal处理的URL无须包含那些怪怪的字符。通常我们把这样的URL称为clean URLs
 
如果使用其它web服务器,比如IIS,可以通过使用Windows Internet Server Application Programming Interface(ISAPI)的模块,比如ISAPI Rewrite来使用clean URL的功能。IIS 7 以后的版本直接就能支持Clean URL
 
Drupal请求初始化过程
Drupal的请求初始化处理过程包括一系列的步骤。这些步骤定义在bootstrap.inc文件中,其内容如下如述:
(1)     初始化配置
这一步骤中,Drupal配置其各种内部变量,并建立起网站的base_urlDrupal会使用include_once方法来装载Settings.php文件,同时还装载所有的用来覆盖默认配置的的字符串和变量。关于这一部分内容,请参见sites/all/default/default.settings.php文件中“String Overrides”和“Variable Overrides”那两节。
(2)     初步页面缓存(Early Page Cache)
在某些需要适应高并发的场合,需要启用缓存系统来防止对数据库的过度访问。初步页面缓存这一步骤把一个PHP文件通过include方法引入,在该PHP文件中有一个方法名为page_cache_fastpath(),它会取得控制权并把内容发送回浏览器。这种初步页面缓存的启用需要将page_cache_fastpath这个变量值设置为TRUE,还需要把cache_inc这个变量值设置到正确的文件路径上,才能够把前面所说的需要引入的PHP文件装载成功。可以查看后面关于缓存的那一章节以了解更多。
(3)     初始化数据库
在数据库这一步骤中,首先会决定数据库的类型,并会创建一个初始的连接用于后面的数据库查询。
(4)     基于域名/IP的访问控制
Drupal是可以限制某个IP/域名的访问的,在访问控制这一步骤中,Drupal会检查是否当前请求来自于一个被限制访问的地址或域名。如果是的话,这一请求就会被拒绝。
(5)     初始化Session
Drupal使用了PHP内置的session处理机制,但是它重写了某写session的处理函数,同时使用了它自己的基于数据库的session管理。这一步骤中会为请求初始化或重建session。同时,代表当前用户的全局的$user变量也在这一步骤中被初始化,只不过基于效率的考虑,并不是所有的属性都被赋值(它们会在后面显示调用user_load()时被赋值)
(6)     后期页面缓存(Late Page Cache)
在后期页面缓存步骤中,Drupal会加载足够的代码来决定是否从缓存取得某个页面。这部分代码包括了把数据库中的设置与在初始化配置时创建的数组进行合并,并会检查加载模块代码。如果Session显示当前的页面请求是由一个匿名用户发出的,那么页面缓存就会被调用,用户浏览器会收到从缓存发出的页面,然后运行结束。
(7)     决定语言
在决定语言这一环节,Drupal的多语言系统被初始化,接下来它会决定用什么语言来返回当前页面,这是由当前用户设置以及站点设置所决定。Drupal支持使用多种方式来决定当前的语言,比如使用路径前缀方式,或是域名级别的语言选择。
(8)     路径
在路径这一步骤中,用来处理路径和路径别名的代码被加载。这一步骤使得用户可读式的URL能够被解析,并管理着Drupal内部的路径缓存和查找。
(9)     完整启动
这一步骤实际上完成了整个启动过程,在这一步骤中,通用函数库会被加载,比如,系统的主题,回调函数映射,文件处理,UnicodePHP图片工具,表单的创建和处理,邮件处理,自动排序表格还有结果集分页等功能。Drupal定制的错误处理工具被启用,并且所有启动的模块会被加载。最后,Drupal会调用各个模块的_init钩子,以使得模块有机会在正式处理业务逻辑前进行相应的初始化工作。
 
一旦Drupal完成了整个初始化过程,它的框架的各部分就都进入运行状态。接下来就可以接收真正的浏览器请求,并将请求发到相应的PHP方法。URLPHP方法间的映射是通过回调函数注册来完成的,在映射的同时,还考虑了访问权限的问题。各个模块都通过_menu这个钩子来注册各自的回调函数(关于menu钩子,请看第四章以获取更多内容)。
 
Drupal发现在当前请求URL和某个回调函数间存在着映射时,并且当前用户的权限也可以访问该回调函数,那么Drupal就会将控制权交给该函数,以进行相应的处理。
 
处理一个请求
回调函数负责完成自己的工作,然后会生成相应的数据以返回给客户端。例如,一个请求http://example.com/?q=node/3Drupal接收到,这个URL会映射到函数node_page_view(),它位于node.module中。接下来,Drupal会从数据库中获取该节点的数据,然后放入一个数据结构中,再然后,用页面模板对其进行包装。
 
用页面模板包装数据
使用页面模板(也就是主题)对数据进行包装,将其转换成HTML(或是XML以及其它格式)Drupal会使用管理员已经选定的主题,来给网站一个正确的外观。然后将输入的HTML数据返回给网页浏览器。

 

Your rating: None Average: 2.7 (19 votes)

总结

阅读本章后,关于Drupal是如何工作的,读者应该已经有一个基本的概念,同时读者也应该对Drupal是如何处理一个Web请求也有了大致的了解。构成处理流程的各部分模块,将会在后面的章节进行详细描述。