配置是Drupal启动过程中的第一个阶段,通过函数_drupal_bootstrap_configuration()实现:

function _drupal_bootstrap_configuration() {
set_error_handler('_drupal_error_handler');
set_exception_handler('_drupal_exception_handler'); drupal_environment_initialize();
timer_start('page');
drupal_settings_initialize();
}

错误和异常处理

Drupal实现了自己的错误处理器_drupal_error_handler()和异常处理器_drupal_exception_handler(),抽时间可以研究下具体如何实现的。

set_error_handler('_drupal_error_handler');
set_exception_handler('_drupal_exception_handler');

初始化环境

初始化环境通过函数drupal_environment_initialize()实现。首先,对$_SERVER中的一些变量检查和修改,保证后续需要用到时都是处理过的:

if (!isset($_SERVER['HTTP_REFERER'])) {
$_SERVER['HTTP_REFERER'] = '';
}
if (!isset($_SERVER['SERVER_PROTOCOL']) || ($_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.0' && $_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.1')) {
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
} if (isset($_SERVER['HTTP_HOST'])) {
// As HTTP_HOST is user input, ensure it only contains characters allowed
// in hostnames. See RFC 952 (and RFC 2181).
// $_SERVER['HTTP_HOST'] is lowercased here per specifications.
$_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']);
if (!drupal_valid_http_host($_SERVER['HTTP_HOST'])) {
// HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
exit;
}
}
else {
// Some pre-HTTP/1.1 clients will not send a Host header. Ensure the key is
// defined for E_ALL compliance.
$_SERVER['HTTP_HOST'] = '';
}

再次,检查用户请求的路径,放到$_GET['q']里面:

$_GET['q'] = request_path();

函数request_path()需要判断请求URL中是否有包含?q=XXX这样的查询参数。有时候为了让搜索引擎友好,会重写URL,也会出现http://example.com/node/306这样的情况。

function request_path() {
static $path; if (isset($path)) {
return $path;
} if (isset($_GET['q']) && is_string($_GET['q'])) {
// This is a request with a ?q=foo/bar query string. $_GET['q'] is
// overwritten in drupal_path_initialize(), but request_path() is called
// very early in the bootstrap process, so the original value is saved in
// $path and returned in later calls.
$path = $_GET['q'];
}
elseif (isset($_SERVER['REQUEST_URI'])) {
// This request is either a clean URL, or 'index.php', or nonsense.
// Extract the path from REQUEST_URI.
// $_SERVER['REQUEST_URI'] = /drupal/index.php?debug_host=10.0.2.15&debug_port=10137&debug_session_id=1000这样
// 进过strtok()去掉问号的内容后 $request_path = /drupal/index.php
$request_path = strtok($_SERVER['REQUEST_URI'], '?'); // $_SERVER['SCRIPT_NAME'] = /drupal/index.php
// $base_path_len = strlen(/drupal)
$base_path_len = strlen(rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/')); // Unescape and strip $base_path prefix, leaving q without a leading slash.
// $path = index.php
$path = substr(urldecode($request_path), $base_path_len + 1); // If the path equals the script filename, either because 'index.php' was
// explicitly provided in the URL, or because the server added it to
// $_SERVER['REQUEST_URI'] even when it wasn't provided in the URL (some
// versions of Microsoft IIS do this), the front page should be served.
// $_SERVER['PHP_SELF'] = /drupal/index.php
if ($path == basename($_SERVER['PHP_SELF'])) {
$path = '';
} // $_SERVER['REQUEST_URI'] = /drupal/node/306
// $request_path = /drupal/node/306
// $base_path_len = 7, 不变
// $path = node/306
}
else {
// This is the front page.
$path = '';
} // Under certain conditions Apache's RewriteRule directive prepends the value
// assigned to $_GET['q'] with a slash. Moreover we can always have a trailing
// slash in place, hence we need to normalize $_GET['q'].
$path = trim($path, '/'); return $path;
}

然后,修改了一些PHP设置。需要注意一下Drupal使用了cookie来传递会话ID,避免了将会话ID放在查询参数里面,导致请求URI太长:

// Don't escape quotes when reading files from the database, disk, etc.
ini_set('magic_quotes_runtime', '0');
// Use session cookies, not transparent sessions that puts the session id in
// the query string.
ini_set('session.use_cookies', '1');
ini_set('session.use_only_cookies', '1');
ini_set('session.use_trans_sid', '0');
// Don't send HTTP headers using PHP's session handler.
ini_set('session.cache_limiter', 'none');
// Use httponly session cookies.
ini_set('session.cookie_httponly', '1');

初始化设置

初始化设置是通过函数drupal_settings_initialize()完成的。这里的设置是指Drupal的settings.php文件。需要注意的是,这里许多变量都做了global声明,也就是说这些变量在Drupal都是全局的。

global $base_url, $base_path, $base_root;

// Export these settings.php variables to the global namespace.
global $databases, $cookie_domain, $conf, $installed_profile, $update_free_access, $db_url, $db_prefix, $drupal_hash_salt, $is_https, $base_secure_url, $base_insecure_url;

首先,直接导入settings.php文件:

if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
include_once DRUPAL_ROOT . '/' . conf_path() . '/settings.php';
}

conf_path()用来处理多站点的情形,具体可以参看《Drupal配置文件settings.php搜索规则》。
settings.php文件必须申明数据库连接信息$databases。另外的,也可以设置Drupal配置变量。在settings.php文件中设置的配置变量具有最高优先级,会覆盖掉后台数据库variable表中的变量,这些变量可以通过variable_get()和variable_set()访问,可以参考《Drupal如何处理系统变量》。例如,可以在settings.php设置代理信息:

$conf['proxy_server'] = '';
$conf['proxy_port'] = 8080;
$conf['proxy_username'] = '';
$conf['proxy_password'] = '';
$conf['proxy_user_agent'] = '';
$conf['proxy_exceptions'] = array('127.0.0.1', 'localhost');

然后,处理各种与URL有关的信息:

$is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';

if (isset($base_url)) {
// Parse fixed base URL from settings.php.
$parts = parse_url($base_url);
if (!isset($parts['path'])) {
$parts['path'] = '';
}
$base_path = $parts['path'] . '/';
// Build $base_root (everything until first slash after "scheme://").
$base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
}
else {
// Create base URL.
$http_protocol = $is_https ? 'https' : 'http'; // http://localhost
$base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST']; $base_url = $base_root; // $_SERVER['SCRIPT_NAME'] can, in contrast to $_SERVER['PHP_SELF'], not
// be modified by a visitor.
if ($dir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/')) {
$base_path = $dir;
$base_url .= $base_path;
$base_path .= '/';
}
else {
$base_path = '/';
} // $base_path = /drupal/
// $base_url = http://localhost/drupal/
} $base_secure_url = str_replace('http://', 'https://', $base_url);
$base_insecure_url = str_replace('https://', 'http://', $base_url);

最后,处理Cookie和会话有关的信息:

if ($cookie_domain) {
// If the user specifies the cookie domain, also use it for session name.
$session_name = $cookie_domain;
}
else {
// Otherwise use $base_url as session name, without the protocol
// to use the same session identifiers across HTTP and HTTPS.
list( , $session_name) = explode('://', $base_url, 2);
// 最后的会话Cookie名称是 session_name('SESS' . substr(hash('sha256', 'localhost/drupal'), 0, 32)) // HTTP_HOST can be modified by a visitor, but we already sanitized it
// in drupal_settings_initialize().
if (!empty($_SERVER['HTTP_HOST'])) {
$cookie_domain = $_SERVER['HTTP_HOST'];
// Strip leading periods, www., and port numbers from cookie domain.
$cookie_domain = ltrim($cookie_domain, '.');
if (strpos($cookie_domain, 'www.') === 0) {
$cookie_domain = substr($cookie_domain, 4);
}
$cookie_domain = explode(':', $cookie_domain);
$cookie_domain = '.' . $cookie_domain[0];
}
}
// Per RFC 2109, cookie domains must contain at least one dot other than the
// first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
ini_set('session.cookie_domain', $cookie_domain);
}
// To prevent session cookies from being hijacked, a user can configure the
// SSL version of their website to only transfer session cookies via SSL by
// using PHP's session.cookie_secure setting. The browser will then use two
// separate session cookies for the HTTPS and HTTP versions of the site. So we
// must use different session identifiers for HTTPS and HTTP to prevent a
// cookie collision.
if ($is_https) {
ini_set('session.cookie_secure', TRUE);
}
$prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
session_name($prefix . substr(hash('sha256', $session_name), 0, 32));

这里说明一下,Drupal的会话Cookie名称使用了SESS前缀再加上URL路径的形式:

session_name('SESS' . substr(hash('sha256', 'localhost/drupal'), 0, 32))

透过Chrome浏览器可以很直观地看到这一点:

Drupal启动阶段之一:配置的更多相关文章

  1. Drupal启动阶段之三:数据库

    Drupal在数据库启动阶段仅仅是简单地包含了database.inc文件,然后再注册类加载器: function _drupal_bootstrap_database() { // Initiali ...

  2. Drupal启动阶段之四:系统变量

    Drupal的系统变量是指保存在后台数据库variable表中的一些参数设置,透过variable_get()和variable_set()存取: 先看一看_drupal_bootstrap_vari ...

  3. Drupal启动阶段之六:页面头信息

    Drupal在本阶段为用户设置缓存头信息.Drupal不为验证用户缓存页面,每次请求时都是从新读取的. function _drupal_bootstrap_page_header() { boots ...

  4. Drupal启动阶段之二:页面缓存

    页面缓存是什么意思?有些页面浏览量非常大,而且与状态无关,这类页面就可以使用页面缓存技术.在页面第一次请求完毕以后,将响应结果保存起来.下一次再请求同一页面时,就不需要从头到尾再执行一遍,只需要将第一 ...

  5. asp.net core 3.x 身份验证-2启动阶段的配置

    注册服务.配置选项.添加身份验证方案 在Startup.ConfigureServices执行services.AddAuthentication() 注册如下服务(便于理解省略了部分辅助服务): s ...

  6. uboot启动阶段修改启动参数方法及分析

    作者:围补 本来启动方式这节不是什么复杂的事儿,不过想简单的说清楚明白,还真是不知道怎么组织.毕竟文字跟有声语言表达有别.但愿简单的东西别让我讲的太复杂! Arm板系统文件一般有三个——bootloa ...

  7. Drupal启动过程

    Drupal整个启动过程共分为8个阶段: DRUPAL_BOOTSTRAP_CONFIGURATION:initialize configuration DRUPAL_BOOTSTRAP_PAGE_C ...

  8. tiny4412 串口驱动分析七 --- log打印的几个阶段之内核启动阶段(earlyprintk)

    作者:彭东林 邮箱:pengdonglin137@163.com 开发板:tiny4412ADK+S700 4GB Flash 主机:Wind7 64位 虚拟机:Vmware+Ubuntu12_04 ...

  9. swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?

    date: 2018-8-01 14:22:17title: swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?description: 阅读 sowft 框架源码, 了解 sowf ...

随机推荐

  1. python itertools的使用(转)

    1. chain的使用 import itertools listone = ['a','b','c'] listtwo = ['11','22','abc'] for item in itertoo ...

  2. Spring 概念详解

    一.Spring的IoC(Inversion of Control). 这是Spring中得有特点的一部份.IoC又被翻译成“控制反转”,也不知道是谁翻译得这么别扭,感觉很深奥的词.其实,原理很简单, ...

  3. bootstrapTable定位行固定滚动条

    写在前面: 当页面table列表数据有修改后,用户需要再次回到修改的行位置. 1.当修改行数据后,table刷新,行数据位置前后不发生改变 ,可使用下面这种方法: /*获取当前滚动条的位置*/ var ...

  4. File I/O知识点

    问题1:File类的作用? 解答:File 类用于访问文件或目录的属性.File类位于java.io包中. 问题2:流?及流的分类? 解答:流是指一连串流动的字符,是以先进先出的方式发送信息的通道.程 ...

  5. Java程序运行时内存划分

    1.Java程序跨平台运行的原因 主要原因是:各种平台的JVM和字节码文件 Java源程序--具体平台的机器代码文件---被编译器翻译成平台无关的Class文件,又用特定JVM运行字节码文件,JVM在 ...

  6. Codeforces Round #344 (Div. 2) E. Product Sum 维护凸壳

    E. Product Sum 题目连接: http://www.codeforces.com/contest/631/problem/E Description Blake is the boss o ...

  7. 关于abstract class 和 interface

    1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系.但是,一个类却可以实现多个interface. 2.在abstract class 中可以有自己 ...

  8. KVM使用virsh console无法连接的解决办法(转)

    一.问题描述: KVM中宿主机通过console无法连接客户机,卡在这里不动. # virsh console vm01 Connected to domain vm01 Escape charact ...

  9. CentOS 5/6安装后的必备设置(转)

    说明:转自各大优化方案,相当于是一个大杂烩,后续会搞成是一个Shell脚本简化操作. 1.修改ip地址.网关.主机名.DNS等 (这个操作可以使用Setup工具进行配置,但不建议使用,封装太多,没有配 ...

  10. awk算术运算一例:统计hdfs上某段时间内的文件大小

    计算hdfs指定目录中所有文件名中包含2011-04-24的文件大小,并换算成GB:  $HADOOP_HOME/bin/hadoop fs -du /user/hdfs/s3/ifocus/*201 ...