Drupal启动阶段之一:配置
配置是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启动阶段之一:配置的更多相关文章
- Drupal启动阶段之三:数据库
Drupal在数据库启动阶段仅仅是简单地包含了database.inc文件,然后再注册类加载器: function _drupal_bootstrap_database() { // Initiali ...
- Drupal启动阶段之四:系统变量
Drupal的系统变量是指保存在后台数据库variable表中的一些参数设置,透过variable_get()和variable_set()存取: 先看一看_drupal_bootstrap_vari ...
- Drupal启动阶段之六:页面头信息
Drupal在本阶段为用户设置缓存头信息.Drupal不为验证用户缓存页面,每次请求时都是从新读取的. function _drupal_bootstrap_page_header() { boots ...
- Drupal启动阶段之二:页面缓存
页面缓存是什么意思?有些页面浏览量非常大,而且与状态无关,这类页面就可以使用页面缓存技术.在页面第一次请求完毕以后,将响应结果保存起来.下一次再请求同一页面时,就不需要从头到尾再执行一遍,只需要将第一 ...
- asp.net core 3.x 身份验证-2启动阶段的配置
注册服务.配置选项.添加身份验证方案 在Startup.ConfigureServices执行services.AddAuthentication() 注册如下服务(便于理解省略了部分辅助服务): s ...
- uboot启动阶段修改启动参数方法及分析
作者:围补 本来启动方式这节不是什么复杂的事儿,不过想简单的说清楚明白,还真是不知道怎么组织.毕竟文字跟有声语言表达有别.但愿简单的东西别让我讲的太复杂! Arm板系统文件一般有三个——bootloa ...
- Drupal启动过程
Drupal整个启动过程共分为8个阶段: DRUPAL_BOOTSTRAP_CONFIGURATION:initialize configuration DRUPAL_BOOTSTRAP_PAGE_C ...
- tiny4412 串口驱动分析七 --- log打印的几个阶段之内核启动阶段(earlyprintk)
作者:彭东林 邮箱:pengdonglin137@163.com 开发板:tiny4412ADK+S700 4GB Flash 主机:Wind7 64位 虚拟机:Vmware+Ubuntu12_04 ...
- swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?
date: 2018-8-01 14:22:17title: swoft| 源码解读系列二: 启动阶段, swoft 都干了些啥?description: 阅读 sowft 框架源码, 了解 sowf ...
随机推荐
- UML功能模型(用例图)
在UML系统开发中有三个主要的模型:功能模型(从用户角度展示系统的功能,包括用例图).对象模型(采用对象,属性,操作关联等概念展示系统的结构和基础,包括类图.对象图.包图).动态模型(展示系统 ...
- 【BZOJ 3166】【HEOI 2013】Alo
http://www.lydsy.com/JudgeOnline/problem.php?id=3166 这道题难点在于求能对一个次大值有贡献的区间. 设这个次大值为\(a_i\),\(a_i\)左边 ...
- ZOJ 3057 Beans Game 博弈论 sg函数
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3057 典型的sg函数,数据范围卡得真好啊 代码 #include<c ...
- [BZOJ2216]Lightning Conductor
原来决策单调性指的是这个东西... 一些DP可以写成$f_i=\max\limits_{j\lt i}g(i,j)$,设$p_i(p_i<j)$表示使得$g(i,j)$最大的$j$,如果$p_1 ...
- 【暴力】hdu6121 Build a tree
给你n,K,让你构造出一颗n个结点的完全K叉树,求所有结点子树大小的异或和. 先把n号结点到根的路径提取出来单独计算.然后这条路径把每一层分成了左右两部分,每一层的左侧和其上一层的右侧的结点的子树大小 ...
- 【容斥原理】Codeforces Round #428 (Div. 2) D. Winter is here
给你一个序列,让你对于所有gcd不为1的子序列,计算它们的gcd*其元素个数之和. 设sum(i)为i的倍数的数的个数,可以通过容斥算出来. 具体看这个吧:http://blog.csdn.net/j ...
- HTML5 Video P2P技术研究(转)
说明:之前在Flash时代,可以基于其实现P2P的技术,也就是现在主流的视频网站用的视频技术,不过要实现P2P技术,在Flash时代有点难,且要服务器支持等等:但是现在基于HTML5技术的P2P技术使 ...
- realloc 用法
#include <stdio.h> #include <stdlib.h> #include <string> int main() { char * p_cha ...
- 粗览Activiti Modeler操作和源代码
Activiti Model Editor组件 我的 了解ActivitiExplorer及其Vaadin实现方式博文里提到ActivitiExplorer使用的是Vaadin架构,但是Activit ...
- Xcode no visible @interface for XXX declares
出现如上面的错误, 是因为没有找到这个方法, 要自己写一个这样的方法 , 如果这是个类目的方法的话, 需要在Target->Linking->Other Linker Flags中添加- ...