第一章 Drupal的工作原理

老葛的Drupal培训班 http://www.thinkindrupal.com

在本章中,我们将为你展示Drupal的概貌。我们将会在以后章节中,对Drupal中的每个部分的工作原理进行详细的介绍。在这里,我们将讨论Drupal运行所用到的技术堆栈, Drupal包含的各种文件,和Drupal使用的各种不同的概念术语,比如节点,钩子,区块和主题。
 
      什么是Drupal
       Drupal是用来构建网站的。它是一个高度模块化,开源的web内容管理框架,并且非常注重合作,互动的重要性。它的特点包括可扩展性强,符合标准,追求简洁代码,内核精练。Drupal自带了一些基本的核心功能,其它的额外功能可通过安装模块核心可选模块或者第3方模块来实现。我们可以基于Drupal进行定制,但是定制是通过覆写核心模块或者增加模块来完成的,而不是修改核心组件中的代码。它还将内容管理和内容表示这二者进行了成功的分离。
     Drupal可被用来构建一个互联网门户;个人的,部门的,或者公司的网站;一个电子商务站点;一个资源分类站点;一个在线报纸;一个图库;一个内部网,Drupal的应用非常广泛,这里仅仅提到了其中的一部分。它甚至可用于远程教育。
    有一个专门的安全小组,他们通过对回应危害和发布安全更新来保证Drupal的安全。另外还有一个非营利性的组织,Drupal协会,它通过改进drupal.org网站的基础设施,组织Drupal聚会和各种活动,来推动Drupal的发展。Drupal的社区也非常活跃,里面包括各种用户,站点管理员,设计者,和web开发者,大家都在非常努力的工作着,并不断地改进着Drupal系统;可参看http://drupal.orghttp://groups.drupal.org

Drupal版本:

技术堆栈

老葛的Drupal培训班 http://www.thinkindrupal.com

Drupal的设计目标是,既可以运行在廉价的Web虚拟主机上,也可以适应高负载的分布式站点。前一个目标则意味着需要使用最流行的技术,而后者则意味着严谨的编码。Drupal的技术堆栈如图1-1所示。
 
 
图1-1 Drupal的技术堆栈
 
     操作系统位于技术堆栈的最底层,Drupal基本不用关心底层的操作系统。只要它支持PHP,就可以运行Drupal。
 
    Drupal最常用的web服务器是Apache,当然也可以使用其它的web服务器(包括微软的IIS)。由于Drupal和Apache的这种长期的友好关系,所以在Drupal的根目录下自带了一个.htaccess,用来确保Drupal安装的安全。可以使用Apache的mod_rewrite模块来实现简洁(Clean)URLs---将URL中的“?”,“&”以及其它奇怪的符号清除掉,在Drupal中去掉的是“?q=”。这一点特别重要,当从其它的内容管理系统或者静态文件中迁移到Drupal上时,依照Tim Berners-Lee(http://www.w3.org/Provider/Style/URI),内容的URL不需要改变,而不改变URI则有利于SEO。对于其它的web服务器,通过使用它的URL重写能力,也可以实现简洁URL。
 
    Drupal使用一个轻量级的数据库抽象层与堆栈的下一层次(数据库层)进行交互。这一抽象层能够处理SQL语句的安全清理;通过使用Drupal数据库API,你不须重构代码,便可以使用不同厂商的数据库。在Drupal中最常用的数据库是MySQL 和 PostgreSQL,不过对Microsoft SQL和Oracle的支持也在不断增加。
 

    Drupal使用的编程语言是PHP。因为PHP比较好学,所以大量的PHP代码都是由新手编写的。而新手的水平大家也知道,他们所写的代码总是存在这样或者那样的问题,这就给PHP的名声带来了比较坏的影响。然而, PHP也可以用于构建严谨的代码。Drupal核心中的所有代码都遵守了严格的编码规范(http://drupal.org/nodes/318),通过开源,其代码也经过了成千上万人的锤炼。对于Drupal来讲,PHP的入门门槛比较低,这就意味着有更多的人能够为Drupal贡献代码,通过开源,会有很多人对这些代码进行检查,这样就保证了代码的质量。通过向社区贡献代码,这样就可以收到他人的反馈,帮助,从而提高大家的技能。

Drupal版本:

核心

 老葛的Drupal培训班 http://www.thinkindrupal.com

Drupal的核心是由一个轻量级的框架构成的。当你从drupal.org下载Drupal时,得到的就是Drupal核心。它负责提供基本的功能,用以支持系统的其它部分。
     内核包括当Drupal接到请求时所要调用的系统引导指令的代码,一个Drupal常用函数库,和提供基本功能的模块比如用户管理、分类、和模板,如图1-2所示。
1-2 Drupal内核的概貌(没有展示完所有的核心功能)

 

Drupal版本:

后台管理界面

     老葛的Drupal培训班 http://www.thinkindrupal.com

    Drupal的后台管理界面与站点的前台部分紧密的集成在了一起,并且在默认情况下,使用相同的主题。第一个用户,也就是用户1,是一个超级用户,他对站点拥有全部权限。以用户1的身份登录后,你将在你的用户区块(参看“区块”部分)中看到管理站点的一个链接。点击这一链接,你将进入到Drupal的后台管理界面。根据用户对站点访问权限的不同,每个用户的区块都会有一个不同的链接。

Drupal版本:

模块

老葛的Drupal培训班 http://www.thinkindrupal.com

Drupal是一个完全模块化的框架。模块中包含了各种功能,而模块可被启用或者禁用(一些必须的模块不能被禁用)。有3种方式可以用来向Drupal站点添加特性:启用已有模块,安装Drupal第3方模块,编写自己的模块。这样,就可以根据站点的需要来添加相应的模块,需要的功能少,则所需的模块也就少;需要功能多,则所需的模块也就多。如图1-3所示。
1-3 通过启用其它模块来添加更多的功能
    新增的内容类型比如处方、日志、或者文件,新增的行为比如e-mail通知、P2P发布、和聚合,等等都是通过模块来实现的。Drupal使用了反转控制(IOC)设计模式,这样框架就会适时的调用相应的模块化功能了。这些为了模块完成它们的任务所提供的机会,被称为钩子

Drupal版本:

钩子

老葛的Drupal培训班 http://www.thinkindrupal.com

可以把钩子看做Drupal的内部事件。有时也将其称为回调函数,这是由于它们是根据函数命名约定来构建的,而不是注册一个事件监听器(listener),它们也不是真的被回调。模块通过使用钩子,就可以与Drupal的其它部分整合在一起了。
 
    假定有一个用户登录了你的Drupal站点。在用户登录时,Drupal调用用户钩子。这意味将调用所有的根据约定——“模块名”+“钩子名”——创建的函数。例如,评论模块中的comment_user(),本地化模块中的locale_user(),节点模块中的node_user(),还有任何其它具有类似名称的函数也都将被调用。如果你编写了一个名为spammy.module的定制模块,其中包含一个名为spammy_user()的函数,用来向用户发送电子邮件,那么你的这个函数也将被调用,倒霉的用户每次登录都将收到一封不请自来的电子邮件。
 
Drupal核心功能进行交互的最常用的方式,就是在模块中实现钩子。
 
提示 更多Drupal支持的钩子的信息,可参看在线文档http://api.drupal.org/api/6,查看“Drupal的组成部分”,接着“模块系统(Drupal钩子)”。
 

Drupal版本:

主题

老葛的Drupal培训班 http://www.thinkindrupal.com

当创建一个web页面,以发送给浏览器时,实际上主要考虑两个方面:把所需的数据收集起来,为这些数据添加HTML标签。在Drupal中,主题层用来负责创建HTML(或者JSON,XML等等),以传递给浏览器。Drupal可以使用多种流行的模板方式,比如Smarty,PHP模板属性语言 (PHPTAL),和PHPTemplate。
 
     这里需要记住的要点是,Drupal提倡将内容和标记区别开来。
 
    在Drupal中可以使用多种方式来为你的网站定制外观。最简单的方式是使用CSS来覆盖Drupal内置的类和ID。然而,如果你不想局限于此,并且想定制实际的HTML输出时,你会发现很容易就可以实现你的目标。Drupal的模板文件由标准的HTML和PHP组成。另外,Drupal页面的每个动态部分(比如盒子、列表、或者面包屑),都可以通过声明一个具有合适名字的函数进行覆写。接着,Drupal将使用你的函数来创建页面的该部分。

Drupal版本:

节点

老葛的Drupal培训班 http://www.thinkindrupal.com

    Drupal中的内容类型,都根源于一个唯一的基本类型,在这里称之为节点。无论它是一篇日志、一个处方,甚至一个工程任务,它的底层数据结构都是相同的。采用这种方式的优势在于它的扩展性。模块开发者可以为节点添加各种特性,比如评分、评论、文件附件、地理位置信息等等,而不用担心节点的具体类型,无管它是日志、处方还是其它。站点管理员可以根据内容类型混合和匹配功能;例如在日志而不是在处方上启用评论,或者仅为工程任务启用文件上传功能。
 
    节点还包含了一个基本的行为属性集,而所有其它的内容类型都继承了这一属性集。任何节点都可以被推到首页、发布或者未发布,或者甚至被搜索。正是由于这个统一的结构,后台管理界面才能够为节点提供了一个批量编辑页面。

Drupal版本:

区块

老葛的Drupal培训班 http://www.thinkindrupal.com

    区块是在你网站模板的特定位置上,可以启用或者禁用的信息。例如,一个区块可以用来显示你站点当前用户的在线人数。你可以区块中包含一些链接,用来指向站点的热门内容,或者包含一些即将到来的事件列表。区块一般放置在模板中的边栏、页首、或者页尾中。区块也可以用来显示特定类型的节点,一般仅用于首页,或者根据其它标准才这样实现。
 
    区块常常用于为当前用户显示定制的信息。例如,用户区块中仅包含了当前用户有权访问的后台管理界面的链接,比如“我的账号”。区块放到区域(比如页首,页脚,或者左右边栏等等)中,而区域则定义在站点的主题中。可以通过后台管理接口页面,对这些区域中区块的位置和可视性进行管理。

Drupal版本:

文件布局

老葛的Drupal培训班 http://www.thinkindrupal.com

通过了解Drupal默认安装的目录结构,能够学会一些重要的最佳实践,比如下载的模块和主题的放置位置,如何拥有不同的Drupal安装轮廓。一个Drupal默认安装的目录结构如图1-4所示。
1-4 Drupal默认安装的目录结构
 
    文件夹目录中的每一元素的详解如下:
 
includes :包含了Drupal常用的函数库。
 
misc:用来存储Drupal安装中可用的JavaScript,和其它各种图标和图片文件。
 
modules:包含了所有核心模块,其中一个模块对应一个文件夹。最好不要乱动这个文件夹(包括profiles和sites以外的其它目录)下面的任何东西,你要添加的其它模块须放到sites目录下。
 
profiles:包含一个站点的不同安装轮廓。如果在这个子目录下面,除了默认的轮廓以外,还有其它的轮廓,那么在你第一次安装你的Drupal站点时,Drupal将向你询问想要安装哪一个轮廓。安装轮廓的主要目的是,用来自动的启用核心的或者第3方的模块。比如一个电子商务轮廓,它将自动把Drupal安装成为一个电子商务平台。
 
scripts:包含了许多脚本,这些脚本可用于语法检查,代码清洁,从命令行运行Drupal,使用cron处理特定情况等等。在Drupal的请求生命周期中,用不到它;里面包含一些shell和Perl的实用脚本。
 
sites:包含了你对Drupal所进行的修改,包括设置、模块、主题等形式(参看图1-5)。你从第3方模块库中下载的模块,或者你自己编写的模块,都放在sites/all/modules下面。这使得你对Drupal所进行的任何修改都保存在单个文件夹里。在目录sites下面有一个名为default的子目录,里面包含了你的Drupal站点的默认的设置文件--- default.settings.php。Drupal安装器,将会基于你提供的信息来修改这些原始设置,并为你的站点创建一个settings.php文件。站点的部署人员,通常会拷贝默认目录,并将其重命名为你站点的URL,所以你最终的设置文件就位于sites/www.example.com/settings.php.
 
sites/default/files:Drupal默认是不包含这个文件夹,但是当你需要上传文件接着提供对外访问时,就需要用到这个目录了。一些示例包括,定制的logo,启用用户头像,或者向你的站点上传其它媒体文件时,你就用到了这个文件夹。运行Drupal的web服务器需要具有对这个子目录进行读和写的权限。如果可以的话,Drupal的安装器将会为你自动的创建这个子目录,并检查是否设置了相应的权限。
 
themes:包含了Drupal的模板引擎和默认主题。你下载的或者创建的其它主题,不能放在这里;应该放在sites/all/ themes中。
 
cron.php:用来执行周期性任务,比如清理过期缓存数据,以及计算统计信息。
 
index.php:处理请求的主入口。
 
install.php: Drupal安装器的主入口。
 
update.php: Drupal版本升级后,用来更新数据库模式(schema)。
 
xmlrpc.php: 用来接收XML-RPC请求,如果你的网站不打算接收XML-RPC请求的话,那么可以将其从中删除。
 
robots.txt:它是搜索引擎爬虫排除标准的默认实现。
 
    在这里没有列出的其它文件都是文档文件。
1-5 sites文件夹用来存储你Drupal所做的修改

Drupal版本:

服务一个请求

老葛的Drupal培训班 http://www.thinkindrupal.com

Drupal收到一个请求时都发生了什么呢?如果对此能有一个概括性的了解,那么对以后的学习将会很有帮助,所以本部分将对这一框架提供一个简要的介绍。如果你自己也想追踪一下的话,使用一个好的调试器,从index.php开始就可以了,Drupal的大多数请求都从这里开始。对于一个简单web页面,这里所列的序列看起来有些复杂,但这也是灵活性所必需的。
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.将这个路径指定给URL查询参数q。
4.Drupal把foo/bar作为Drupal内部路径,并在index.php中开始进行处理。
 
    这一流程的结果就是,Drupal对http://example.com/foo/barhttp://example.com/index.php?q=foo/bar的处理方式是一样的,因为对于Drupal来说,这两者的内部路径是一样的。这就使得Drupal可以使用不带“?q=”的URL了。这些URL被称为简洁URL。
 
    在备选的web服务器中,比如微软的IIS,可以使用一个ISAPI模块比如ISAPI_Rewrite来实现简洁URL。IIS 7及以后的版本可能会内置对重写的支持。

Drupal版本:

引导指令流程

老葛的Drupal培训班 http://www.thinkindrupal.com

引导指令流程
    对于每个请求,Drupal引导指令本身都会经历一系列的引导指令阶段。这些阶段定义在bootstrap.inc中,在接下来的部分中,我们将会为你描述处理流程。
 
初始配置
     在这一阶段,将会填充Drupal的内部配置数组,并建立站点的基URL($base_url)。通过include_once()来解析settings.php文件,任何已被覆写的变量或者字符串都可被应用了。详情请参看sites/all/default/default.settings.php文件中的“变量覆写”和“字符串覆写”部分。
 
前期页面缓存
    在有些情况下,可能会需要更高水平的性能,甚至在建立数据库连接之前,可能就需要要调用缓存系统了。前期页面缓存阶段,会让你(使用include())包含一个PHP文件,里面带有一个名为page_cache_fastpath()的函数,该函数接收内容并将其返回给浏览器。通过将page_cache_fastpath变量设置为TRUE,就可以启用早期页面缓存阶段了,而包含进来的文件则通过将cache_inc变量设置为文件的路径来定义。具体示例可参看缓存一章。
 
初始化数据库
    在数据库阶段期间,将决定数据库的类型,将建立初始化链接以供数据库查询使用。
 
基于主机名/ID地址进行访问控制
    Drupal支持基于主机名/ IP地址来禁止主机(对站点的访问)。在访问控制阶段,会快速的检查请求是否来自一个被禁的主机;如果是,那么将拒绝访问。
 
初始化会话处理
    Drupal利用了PHP内置的会话处理,但是它使用自己的基于数据库的会话处理器,覆写了PHP的一些处理器。在会话阶段,将初始化或者重新构建会话。代表当前用户的全局对象$User也会在这一阶段初始化,不过出去效率的原因,并不是对象的所有属性都是可用的(当需要时,可以通过明确的调用函数user_load()来加载这些属性)。
 
后期页面缓存
    在后期页面缓存阶段,Drupal会加载足够的支持代码,来决定是否需要从页面缓存中提供一个页面。这包括,把来自于数据库的设置合并到在初始化配置阶段创建的数组中,并且加载或者解析模块代码。如果在会话中显示请求来自于匿名用户,并启用了页面缓存,那么将从缓存中返回页面,执行将在此停止。
 
语言判定
    在语言判定阶段,将会初始化Drupal的多语言支持,并基于站点和用户的设置,来决定为当前页面使用哪一个语言。Drupal支持多种方式来判定语言,比如路径前缀和域名层的语言判断。
 
路径

     在路径阶段,将加载处理路径和路径别名的代码。该阶段使得用户可读的URL被转化为Drupal路径,并处理Drupal内部路径的缓存和查找操作。

Drupal版本:

完成

老葛的Drupal培训班 http://www.thinkindrupal.com

完成
    该阶段是引导指令的最后一个阶段,它包括加载一个通用函数库,主题支持,和支持回调映射,文件处理,Unicode,PHP图片工具集,表单的创建和处理,自动排序的表格,和结果集的分页。在这里将设置Drupal定制的错误处理器,并加载所有启用了的模块。最后Drupal调用init钩子,这样在对请求正式开始处理以前,将有机会通知相应的模块。
 
    一旦Drupal整个引导指令完成以后,那么框架中的所有部分现在都可以使用了。现在就可以获得浏览器的请求并将它委托给一个处理函数。在URLs和处理函数之间的映射,是使用一个回调登记来完成的,这个回调登记负责URL映射和访问控制。模块使用菜单钩子来注册它们的回调函数(更多信息,参看第4章)
 
    对于浏览器请求的URL,如果Drupal为其找到一个存在的映射回调函数,并且用户有权访问此回调函数,那么控制权将转移给回调函数。
 
处理一个请求
    回调函数完成了流程所要做的事情,并收集完成请求所需要的数据。例如,收到了一个对内容的请求比如http://example.com/q=node/3,URL将被映射到node.module里面的函数node_page_view()上。进一步的处理包括,将从数据库中取回该节点的数据,并将它放到一个数组中。接着,就到了主题化的时候了。
 
主题化数据
    主题化涉及到将已被取回,操作过或者创建了的数据转化为HTML(或者XML以及其它输出格式)。Drupal将使用管理员选用的主题,来为网页提供一个合适的外观,并将生成的HTML返回给web浏览器。

Drupal版本:

总结

老葛的Drupal培训班 http://www.thinkindrupal.com

总结
    读完本章后,你应该能大致的了解Drupal的工作原理,并对当Drupal为一个请求服务时都发生了什么有个概念。对于该服务处理流程的各个部分,我们将会在后面章节中作出详细介绍。

Drupal版本: