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 ...
随机推荐
- 【状压dp】Islands and Bridges
Islands and Bridges Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 11034 Accepted: 2 ...
- BZOJ 4236 JOIOJI(前缀和)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4236 [题目大意] 给出一个只包含三种字母的字符串,求出三种字母数量相等的最长子串 [ ...
- 【计算几何】【凸包】【极角排序】【二分】Gym - 101128J - Saint John Festival
平面上n个红点,m个黑点,问你多少个黑点至少在一个红三角形内. 对红点求凸包后,转化为询问有多少个黑点在凸包内. 点在凸多边形内部判定,选定一个凸包上的点作原点,对凸包三角剖分,将其他的点极角排序之后 ...
- 【动态规划】【线段树】 Codeforces Round #426 (Div. 1) B. The Bakery
给你一个序列,让你划分成K段,每段的价值是其内部权值的种类数,让你最大化所有段的价值之和. 裸dp f(i,j)=max{f(k,j-1)+w(k+1,i)}(0<=k<i) 先枚举j,然 ...
- 【最短路】【spfa】CDOJ1647 酌贪泉而觉爽, 处涸辙以犹欢。
题意: 给你一个全为0的01串,问你能否通过一系列的变换,得到全为1的01串. 分析: 将每个01串看作一个点,每一个变换可以看作是一条有向边,现在问题可以转化 为找从“00..0”这个点到“11.. ...
- 【最大权闭合图】BZOJ1565-[NOI2009]植物大战僵尸
害怕地发现我以前写的Dinic几乎都是有错的……??!!! [题目大意] (以下摘自popoqqq大爷)给定一个m*n的草坪,每块草坪上的植物有两个属性:1.啃掉这个植物,获得收益x(可正可负)2.保 ...
- 微信小程序 Session 失效
微信小程序 Session 失效 微信小程序,前端请求后端,中间多了个微信服务器,所以请求的流程就是 页面--微信服务器--目标服务器 这就导致了一个问题 session 每次请求都是一个新的会话 解 ...
- Problem C: 程序改错(递归函数):数字转字符
Description 下面程序中“/ ***** N ***** /”的下一行中有错误,请改正(注意:不得加行.减行.加句.减句,否则后果自负). 该程序功能:用递归法将一个六位整数n转换成字符串, ...
- Web API使用记录系列(四)OAuth授权与身份校验
呼,开干第四篇,基于OWIN搭建OAuth认证授权服务器与接口身份校验. OAuth包含授权码模式.密码模式.客户端模式和简化模式,这里我们文章记录的是密码模式和客户端模式. 目录 引用安装 授权处理 ...
- 莫名其妙的float:left; 不能使元素紧贴父级的坑
这是项目中遇到的一个CSS的坑,做个记录,主要的原因还是浮动后脱离文档流,两个浮动的元素处于同一文档流中会相互影响位置的问题: 先上代码吧: 效果预览地址:浮动不能靠左的情况; 原本红色模块应该处于蓝 ...