Commit a0640e66 authored by Dries's avatar Dries

- Improved module loading when serving cached pages.  Moshe's bootstrap patch.

- Used legend and fieldset tags for the configuration page.
parent 7a2514e7
...@@ -2,6 +2,8 @@ Drupal x.x.x, xxxx-xx-xx ...@@ -2,6 +2,8 @@ Drupal x.x.x, xxxx-xx-xx
------------------------ ------------------------
- added support for the MetaWeblog API and MoveableType extensions. - added support for the MetaWeblog API and MoveableType extensions.
- performance:
* improved module loading when serving cached pages.
- theme system: - theme system:
* made all theme functions start with 'theme_'. * made all theme functions start with 'theme_'.
* made all theme functions return their output. * made all theme functions return their output.
......
<?php <?php
// $Id$ // $Id$
include_once "includes/bootstrap.inc";
include_once "includes/common.inc"; include_once "includes/common.inc";
/* /*
......
...@@ -299,6 +299,7 @@ CREATE TABLE [dbo].[system] ( ...@@ -299,6 +299,7 @@ CREATE TABLE [dbo].[system] (
[type] [varchar] (255) NOT NULL , [type] [varchar] (255) NOT NULL ,
[description] [varchar] (255) NOT NULL , [description] [varchar] (255) NOT NULL ,
[status] [int] NOT NULL [status] [int] NOT NULL
[bootstrap] [int] NOT NULL
) ON [PRIMARY] ) ON [PRIMARY]
GO GO
......
...@@ -426,6 +426,7 @@ CREATE TABLE system ( ...@@ -426,6 +426,7 @@ CREATE TABLE system (
type varchar(255) NOT NULL default '', type varchar(255) NOT NULL default '',
description varchar(255) NOT NULL default '', description varchar(255) NOT NULL default '',
status int(2) NOT NULL default '0', status int(2) NOT NULL default '0',
bootstrap int(2) NOT NULL default '0',
PRIMARY KEY (filename) PRIMARY KEY (filename)
) TYPE=MyISAM; ) TYPE=MyISAM;
......
...@@ -422,6 +422,7 @@ CREATE TABLE system ( ...@@ -422,6 +422,7 @@ CREATE TABLE system (
type varchar(255) NOT NULL default '', type varchar(255) NOT NULL default '',
description varchar(255) NOT NULL default '', description varchar(255) NOT NULL default '',
status integer NOT NULL default '0', status integer NOT NULL default '0',
bootstrap integer NOT NULL default '0',
PRIMARY KEY (filename) PRIMARY KEY (filename)
); );
......
<?php <?php
// $Id$ // $Id$
include_once "includes/bootstrap.inc";
include_once "includes/common.inc"; include_once "includes/common.inc";
$errors = array( $errors = array(
......
<?php
function conf_init() {
/*
** Try finding a matching configuration file by stripping the website's
** URI from left to right. If no configuration file is found, return a
** default value 'conf'.
*/
$uri = $_SERVER["PHP_SELF"];
$file = strtolower(strtr($_SERVER["HTTP_HOST"] . substr($uri, 0, strrpos($uri, "/")), "/:", ".."));
while (strlen($file) > 4) {
if (file_exists("includes/$file.php")) {
return $file;
}
else {
$file = substr($file, strpos($file, ".") + 1);
}
}
return "conf";
}
function variable_init($conf = array()) {
$result = db_query("SELECT * FROM {variable} ");
while ($variable = db_fetch_object($result)) {
if (!isset($conf[$variable->name])) {
$conf[$variable->name] = unserialize($variable->value);
}
}
return $conf;
}
function variable_get($name, $default) {
global $conf;
return isset($conf[$name]) ? $conf[$name] : $default;
}
function variable_set($name, $value) {
global $conf;
db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, serialize($value));
$conf[$name] = $value;
}
function variable_del($name) {
global $conf;
db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
unset($conf[$name]);
}
function cache_get($key) {
$cache = db_fetch_object(db_query("SELECT data, created FROM {cache} WHERE cid = '%s'", $key));
return $cache->data ? $cache : 0;
}
function cache_set($cid, $data, $expire = 0) {
db_query("UPDATE {cache} SET data = '%s', created = %d, expire = %d WHERE cid = '%s'", $data, time(), $expire, $cid);
if (!db_affected_rows()) {
db_query("INSERT INTO {cache} (cid, data, created, expire) VALUES('%s', '%s', %d, %d)", $cid, $data, time(), $expire);
}
}
function cache_clear_all($cid = NULL) {
if (empty($cid)) {
db_query("DELETE FROM {cache} WHERE expire <> 0");
}
else {
db_query("DELETE FROM {cache} WHERE cid = '%s'", $cid);
}
}
function page_set_cache() {
global $user;
if (!$user->uid && $_SERVER["REQUEST_METHOD"] == "GET") {
if ($data = ob_get_contents()) {
cache_set(request_uri(), $data, 1);
}
}
}
function page_get_cache() {
global $user;
$cache = NULL;
if (!$user->uid && $_SERVER["REQUEST_METHOD"] == "GET") {
$cache = cache_get(request_uri());
if (empty($cache)) {
ob_start();
}
}
return $cache;
}
function drupal_page_header() {
if (variable_get("dev_timer", 0)) {
timer_start();
}
if (variable_get("cache", 0)) {
if ($cache = page_get_cache()) {
// Set default values:
$date = gmdate("D, d M Y H:i:s", $cache->created) ." GMT";
$etag = '"'. md5($date) .'"';
// Check http headers:
$modified_since = isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) ? $_SERVER["HTTP_IF_MODIFIED_SINCE"] == $date : NULL;
$none_match = isset($_SERVER["HTTP_IF_NONE_MATCH"]) ? $_SERVER["HTTP_IF_NONE_MATCH"] == $etag : NULL;
// The type checking here is very important, be careful when changing entries.
if (($modified_since !== NULL || $none_match !== NULL) && $modified_since !== false && $none_match !== false) {
header("HTTP/1.0 304 Not Modified");
exit();
}
// Send appropriate response:
header("Last-Modified: $date");
header("ETag: $etag");
print $cache->data;
/*
** call all init() and exit() hooks without including all modules
** only use those hooks for critical operations
*/
foreach (module_list(0, 1) as $module) {
if (is_array($module) && $module['bootstrap']) {
include_once $module['filename'];
foreach (bootstrap_hooks() as $hook) {
module_invoke($module['name'], $hook);
}
}
}
exit();
}
}
}
// critical hooks called even when serving a cached page
function bootstrap_hooks() {
return array('init', 'exit');
}
function referer_uri() {
if (isset($_SERVER["HTTP_REFERER"])) {
$uri = $_SERVER["HTTP_REFERER"];
return check_url($uri);
}
}
function arg($index) {
static $arguments;
if (empty($arguments)) {
$arguments = explode("/", $_GET["q"]);
}
return $arguments[$index];
}
function check_query($text) {
return addslashes($text);
}
function check_url($uri) {
$uri = htmlspecialchars($uri, ENT_QUOTES);
/*
** We replace ( and ) with their entity equivalents to prevent XSS
** attacks.
*/
$uri = strtr($uri, array("(" => "&040;", ")" => "&041;"));
return $uri;
}
function request_uri() {
/*
** Since request_uri() is only available on Apache, we generate
** equivalent using other environment vars.
*/
if (isset($_SERVER["REQUEST_URI"])) {
$uri = $_SERVER["REQUEST_URI"];
}
else {
$uri = $_SERVER["PHP_SELF"] ."?". $_SERVER["QUERY_STRING"];
}
return check_url($uri);
}
function timer_start() {
global $timer;
list($usec, $sec) = explode(" ", microtime());
$timer = (float)$usec + (float)$sec;
}
unset($conf);
$config = conf_init();
include_once "includes/$config.php";
include_once "includes/database.inc";
include_once "includes/session.inc";
include_once "includes/module.inc";
// initialize configuration variables, using values from conf.php if available:
$conf = variable_init(isset($conf) ? $conf : array());
?>
<?php <?php
// $Id$ // $Id$
function conf_init() {
/*
** Try finding a matching configuration file by stripping the website's
** URI from left to right. If no configuration file is found, return a
** default value 'conf'.
*/
$uri = $_SERVER["PHP_SELF"];
$file = strtolower(strtr($_SERVER["HTTP_HOST"] . substr($uri, 0, strrpos($uri, "/")), "/:", ".."));
while (strlen($file) > 4) {
if (file_exists("includes/$file.php")) {
return $file;
}
else {
$file = substr($file, strpos($file, ".") + 1);
}
}
return "conf";
}
/** /**
* Build the alias/path array * Build the alias/path array
*/ */
...@@ -100,17 +76,6 @@ function fix_gpc_magic() { ...@@ -100,17 +76,6 @@ function fix_gpc_magic() {
$fixed = true; $fixed = true;
} }
function arg($index) {
static $arguments;
if (empty($arguments)) {
$arguments = explode("/", $_GET["q"]);
}
return $arguments[$index];
}
function array2object($node) { function array2object($node) {
if (is_array($node)) { if (is_array($node)) {
...@@ -139,31 +104,6 @@ function object2array($node) { ...@@ -139,31 +104,6 @@ function object2array($node) {
return $array; return $array;
} }
function referer_uri() {
if (isset($_SERVER["HTTP_REFERER"])) {
$uri = $_SERVER["HTTP_REFERER"];
return check_url($uri);
}
}
function request_uri() {
/*
** Since request_uri() is only available on Apache, we generate
** equivalent using other environment vars.
*/
if (isset($_SERVER["REQUEST_URI"])) {
$uri = $_SERVER["REQUEST_URI"];
}
else {
$uri = $_SERVER["PHP_SELF"] ."?". $_SERVER["QUERY_STRING"];
}
return check_url($uri);
}
function message_access() { function message_access() {
return t("You are not authorized to access this page."); return t("You are not authorized to access this page.");
} }
...@@ -210,40 +150,6 @@ function t($string, $args = 0) { ...@@ -210,40 +150,6 @@ function t($string, $args = 0) {
} }
} }
function variable_init($conf = array()) {
$result = db_query("SELECT * FROM {variable} ");
while ($variable = db_fetch_object($result)) {
if (!isset($conf[$variable->name])) {
$conf[$variable->name] = unserialize($variable->value);
}
}
return $conf;
}
function variable_get($name, $default) {
global $conf;
return isset($conf[$name]) ? $conf[$name] : $default;
}
function variable_set($name, $value) {
global $conf;
db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, serialize($value));
$conf[$name] = $value;
}
function variable_del($name) {
global $conf;
db_query("DELETE FROM {variable} WHERE name = '%s'", $name);
unset($conf[$name]);
}
function drupal_specialchars($input, $quotes = ENT_NOQUOTES) { function drupal_specialchars($input, $quotes = ENT_NOQUOTES) {
/* /*
...@@ -476,27 +382,10 @@ function valid_input_data($data) { ...@@ -476,27 +382,10 @@ function valid_input_data($data) {
return 1; return 1;
} }
function check_url($uri) {
$uri = htmlspecialchars($uri, ENT_QUOTES);
/*
** We replace ( and ) with their entity equivalents to prevent XSS
** attacks.
*/
$uri = strtr($uri, array("(" => "&040;", ")" => "&041;"));
return $uri;
}
function check_form($text) { function check_form($text) {
return drupal_specialchars($text, ENT_QUOTES); return drupal_specialchars($text, ENT_QUOTES);
} }
function check_query($text) {
return addslashes($text);
}
function filter($text) { function filter($text) {
$modules = module_list(); $modules = module_list();
...@@ -672,53 +561,6 @@ function format_size($size) { ...@@ -672,53 +561,6 @@ function format_size($size) {
return t("%size %suffix", array("%size" => $size, "%suffix" => $suffix)); return t("%size %suffix", array("%size" => $size, "%suffix" => $suffix));
} }
function cache_get($key) {
$cache = db_fetch_object(db_query("SELECT data, created FROM {cache} WHERE cid = '%s'", $key));
return $cache->data ? $cache : 0;
}
function cache_set($cid, $data, $expire = 0) {
db_query("UPDATE {cache} SET data = '%s', created = %d, expire = %d WHERE cid = '%s'", $data, time(), $expire, $cid);
if (!db_affected_rows()) {
db_query("INSERT INTO {cache} (cid, data, created, expire) VALUES('%s', '%s', %d, %d)", $cid, $data, time(), $expire);
}
}
function cache_clear_all($cid = NULL) {
if (empty($cid)) {
db_query("DELETE FROM {cache} WHERE expire <> 0");
}
else {
db_query("DELETE FROM {cache} WHERE cid = '%s'", $cid);
}
}
function page_set_cache() {
global $user;
if (!$user->uid && $_SERVER["REQUEST_METHOD"] == "GET") {
if ($data = ob_get_contents()) {
cache_set(request_uri(), $data, 1);
}
}
}
function page_get_cache() {
global $user;
$cache = NULL;
if (!$user->uid && $_SERVER["REQUEST_METHOD"] == "GET") {
$cache = cache_get(request_uri());
if (empty($cache)) {
ob_start();
}
}
return $cache;
}
function format_interval($timestamp) { function format_interval($timestamp) {
$units = array("1 year|%count years" => 31536000, "1 week|%count weeks" => 604800, "1 day|%count days" => 86400, "1 hour|%count hours" => 3600, "1 min|%count min" => 60, "1 sec|%count sec" => 1); $units = array("1 year|%count years" => 31536000, "1 week|%count weeks" => 604800, "1 day|%count days" => 86400, "1 hour|%count hours" => 3600, "1 min|%count min" => 60, "1 sec|%count sec" => 1);
foreach ($units as $key=>$value) { foreach ($units as $key=>$value) {
...@@ -1005,64 +847,6 @@ function link_node($node, $main = 0) { ...@@ -1005,64 +847,6 @@ function link_node($node, $main = 0) {
return module_invoke_all("link", "node", $node, $main); return module_invoke_all("link", "node", $node, $main);
} }
function timer_start() {
global $timer;
list($usec, $sec) = explode(" ", microtime());
$timer = (float)$usec + (float)$sec;
}
function drupal_page_header() {
if (variable_get("dev_timer", 0)) {
timer_start();
}
if (variable_get("cache", 0)) {
if ($cache = page_get_cache()) {
// Set default values:
$date = gmdate("D, d M Y H:i:s", $cache->created) ." GMT";
$etag = '"'. md5($date) .'"';
// Check http headers:
$modified_since = isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) ? $_SERVER["HTTP_IF_MODIFIED_SINCE"] == $date : NULL;
$none_match = isset($_SERVER["HTTP_IF_NONE_MATCH"]) ? $_SERVER["HTTP_IF_NONE_MATCH"] == $etag : NULL;
// The type checking here is very important, be careful when changing entries.
if (($modified_since !== NULL || $none_match !== NULL) && $modified_since !== false && $none_match !== false) {
header("HTTP/1.0 304 Not Modified");
exit();
}
// Send appropriate response:
header("Last-Modified: $date");
header("ETag: $etag");
print $cache->data;
/*
** A hook for modules where modules may take action at the end of a
** request good uses include setting a cache, page logging, etc.
*/
module_invoke_all("exit");
exit();
}
}
/*
** Putting the check here avoids SQL query overhead in case we are
** serving cached pages. The downside, however, is that the init
** hooks might use unchecked data.
*/
if (!user_access("bypass input data check")) {
if (!valid_input_data($_REQUEST)) {
die("terminated request because of suspicious input data");
}
}
}
function drupal_page_footer() { function drupal_page_footer() {
if (variable_get("cache", 0)) { if (variable_get("cache", 0)) {
page_set_cache(); page_set_cache();
...@@ -1076,22 +860,12 @@ function drupal_page_footer() { ...@@ -1076,22 +860,12 @@ function drupal_page_footer() {
module_invoke_all("exit"); module_invoke_all("exit");
} }
unset($conf);
$config = conf_init();
include_once "includes/$config.php";
include_once "includes/database.inc";
include_once "includes/module.inc";
include_once "includes/theme.inc"; include_once "includes/theme.inc";
include_once "includes/pager.inc"; include_once "includes/pager.inc";
include_once "includes/menu.inc"; include_once "includes/menu.inc";
include_once "includes/xmlrpc.inc"; include_once "includes/xmlrpc.inc";
include_once "includes/tablesort.inc"; include_once "includes/tablesort.inc";
// initialize configuration variables, using values from conf.php if available:
$conf = variable_init(isset($conf) ? $conf : array());
// set error handler: // set error handler:
set_error_handler("error_handler"); set_error_handler("error_handler");
...@@ -1116,9 +890,16 @@ function drupal_page_footer() { ...@@ -1116,9 +890,16 @@ function drupal_page_footer() {
// initialize installed modules: // initialize installed modules:
module_init(); module_init();
if (!user_access("bypass input data check")) {
if (!valid_input_data($_REQUEST)) {
die("terminated request because of suspicious input data");
}
}
// initialize localization system: // initialize localization system:
$locale = locale_init(); $locale =