summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
Diffstat (limited to 'includes')
-rw-r--r--includes/batch.inc7
-rw-r--r--includes/bootstrap.inc70
-rw-r--r--includes/common.inc51
-rw-r--r--includes/form.inc2
-rw-r--r--includes/session.inc78
5 files changed, 164 insertions, 44 deletions
diff --git a/includes/batch.inc b/includes/batch.inc
index 4010acb36..ada7ce8b3 100644
--- a/includes/batch.inc
+++ b/includes/batch.inc
@@ -34,6 +34,11 @@ function _batch_page() {
':token' => drupal_get_token($_REQUEST['id']))
)->fetchField();
+ if (!$batch) {
+ drupal_set_message(t('No active batch.'), 'error');
+ drupal_goto();
+ }
+
$batch = unserialize($batch);
// Register database update for the end of processing.
@@ -409,7 +414,7 @@ function _batch_finished() {
// We get here if $form['#redirect'] was FALSE, or if the form is a
// multi-step form. We save the final $form_state value to be retrieved
// by drupal_get_form(), and redirect to the originating page.
- $_SESSION['batch_form_state'] = $_batch['form_state'];
+ drupal_set_session('batch_form_state', $_batch['form_state']);
drupal_goto($_batch['source_page']);
}
}
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 7eead8055..35a53b01d 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -671,23 +671,41 @@ function variable_del($name) {
/**
* Retrieve the current page from the cache.
*
- * Note: we do not serve cached pages when status messages are waiting (from
- * a redirected form submission which was completed).
+ * Note: we do not serve cached pages to authenticated users, or to anonymous
+ * users when $_SESSION is non-empty. $_SESSION may contain status messages
+ * from a form submission, the contents of a shopping cart, or other user-
+ * specific content that should not be cached and displayed to other users.
+ *
+ * @param $retrieve
+ * If TRUE, look up and return the current page in the cache, or start output
+ * buffering if the conditions for caching are satisfied. If FALSE, only
+ * return a boolean value indicating whether the current request may be
+ * cached.
+ * @return
+ * The cache object, if the page was found in the cache; TRUE if the page was
+ * not found, but output buffering was started in order to possibly cache the
+ * current request; FALSE if the page was not found, and the current request
+ * may not be cached (e.g. because it belongs to an authenticated user). If
+ * $retrieve is TRUE, only return either TRUE or FALSE.
*/
-function page_get_cache() {
+function page_get_cache($retrieve) {
global $user, $base_root;
+ static $ob_started = FALSE;
- $cache = NULL;
-
- if (!$user->uid && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && count(drupal_set_message()) == 0) {
+ if ($user->uid || ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != 'HEAD') || count(drupal_get_messages(NULL, FALSE))) {
+ return FALSE;
+ }
+ if ($retrieve) {
$cache = cache_get($base_root . request_uri(), 'cache_page');
-
- if (empty($cache)) {
+ if ($cache) {
+ return $cache;
+ }
+ else {
ob_start();
+ $ob_started = TRUE;
}
}
-
- return $cache;
+ return $ob_started;
}
/**
@@ -956,7 +974,7 @@ function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NO
function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) {
if ($message) {
if (!isset($_SESSION['messages'])) {
- $_SESSION['messages'] = array();
+ drupal_set_session('messages', array());
}
if (!isset($_SESSION['messages'][$type])) {
@@ -1093,7 +1111,7 @@ function drupal_get_bootstrap_phase() {
}
function _drupal_bootstrap($phase) {
- global $conf;
+ global $conf, $user;
switch ($phase) {
@@ -1139,7 +1157,16 @@ function _drupal_bootstrap($phase) {
case DRUPAL_BOOTSTRAP_SESSION:
require_once DRUPAL_ROOT . '/' . variable_get('session_inc', 'includes/session.inc');
session_set_save_handler('_sess_open', '_sess_close', '_sess_read', '_sess_write', '_sess_destroy_sid', '_sess_gc');
- session_start();
+ // If a session cookie exists, initialize the session. Otherwise the
+ // session is only started on demand in drupal_session_start(), making
+ // anonymous users not use a session cookie unless something is stored in
+ // $_SESSION. This allows HTTP proxies to cache anonymous pageviews.
+ if (isset($_COOKIE[session_name()])) {
+ drupal_session_start();
+ }
+ else {
+ $user = drupal_anonymous_user();
+ }
break;
case DRUPAL_BOOTSTRAP_VARIABLES:
@@ -1150,15 +1177,19 @@ function _drupal_bootstrap($phase) {
case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE:
$cache_mode = variable_get('cache', CACHE_DISABLED);
// Get the page from the cache.
- $cache = $cache_mode == CACHE_DISABLED ? '' : page_get_cache();
+ $cache = $cache_mode == CACHE_DISABLED ? FALSE : page_get_cache(TRUE);
// If the skipping of the bootstrap hooks is not enforced, call hook_boot.
- if (!$cache || $cache_mode != CACHE_AGGRESSIVE) {
+ if (!is_object($cache) || $cache_mode != CACHE_AGGRESSIVE) {
// Load module handling.
require_once DRUPAL_ROOT . '/includes/module.inc';
module_invoke_all('boot');
}
// If there is a cached page, display it.
- if ($cache) {
+ if (is_object($cache)) {
+ // Destroy empty anonymous sessions.
+ if (drupal_session_is_started() && empty($_SESSION)) {
+ session_destroy();
+ }
drupal_page_cache_header($cache);
// If the skipping of the bootstrap hooks is not enforced, call hook_exit.
if ($cache_mode != CACHE_AGGRESSIVE) {
@@ -1169,6 +1200,13 @@ function _drupal_bootstrap($phase) {
}
// Prepare for non-cached page workflow.
drupal_page_header();
+ // If the session has not already been started and output buffering is
+ // not enabled, the session must be started now before the HTTP headers
+ // are sent. If output buffering is enabled, the session may be started
+ // at any time using drupal_session_start().
+ if ($cache === FALSE) {
+ drupal_session_start();
+ }
break;
case DRUPAL_BOOTSTRAP_LANGUAGE:
diff --git a/includes/common.inc b/includes/common.inc
index 6946fa02a..91bed1d05 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -339,9 +339,11 @@ function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response
module_invoke_all('exit', $url);
}
- // Even though session_write_close() is registered as a shutdown function, we
- // need all session data written to the database before redirecting.
- session_write_close();
+ if (drupal_session_is_started()) {
+ // Even though session_write_close() is registered as a shutdown function,
+ // we need all session data written to the database before redirecting.
+ session_write_close();
+ }
header('Location: ' . $url, TRUE, $http_response_code);
@@ -1831,6 +1833,15 @@ function l($text, $path, array $options = array()) {
* react to the closing of the page by calling hook_exit().
*/
function drupal_page_footer() {
+ global $user;
+
+ // Destroy empty anonymous sessions if possible.
+ if (!headers_sent() && drupal_session_is_started() && empty($_SESSION) && !$user->uid) {
+ session_destroy();
+ }
+ elseif (!empty($_SESSION) && !drupal_session_is_started()) {
+ watchdog('session', '$_SESSION is non-empty yet no code has called drupal_session_start().', array(), WATCHDOG_NOTICE);
+ }
if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) {
page_set_cache();
@@ -2971,26 +2982,24 @@ function _drupal_bootstrap_full() {
function page_set_cache() {
global $user, $base_root;
- if (!$user->uid && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && count(drupal_get_messages(NULL, FALSE)) == 0) {
- // This will fail in some cases, see page_get_cache() for the explanation.
- if ($data = ob_get_contents()) {
- $cache = TRUE;
- if (variable_get('page_compression', TRUE) && function_exists('gzencode')) {
- // We do not store the data in case the zlib mode is deflate.
- // This should be rarely happening.
- if (zlib_get_coding_type() == 'deflate') {
- $cache = FALSE;
- }
- elseif (zlib_get_coding_type() == FALSE) {
- $data = gzencode($data, 9, FORCE_GZIP);
- }
- // The remaining case is 'gzip' which means the data is
- // already compressed and nothing left to do but to store it.
+ if (page_get_cache(FALSE)) {
+ $cache = TRUE;
+ $data = ob_get_contents();
+ if (variable_get('page_compression', TRUE) && function_exists('gzencode')) {
+ // We do not store the data in case the zlib mode is deflate. This should
+ // be rarely happening.
+ if (zlib_get_coding_type() == 'deflate') {
+ $cache = FALSE;
}
- ob_end_flush();
- if ($cache && $data) {
- cache_set($base_root . request_uri(), $data, 'cache_page', CACHE_TEMPORARY, drupal_get_headers());
+ elseif (zlib_get_coding_type() == FALSE) {
+ $data = gzencode($data, 9, FORCE_GZIP);
}
+ // The remaining case is 'gzip' which means the data is already
+ // compressed and nothing left to do but to store it.
+ }
+ ob_end_flush();
+ if ($cache && $data) {
+ cache_set($base_root . request_uri(), $data, 'cache_page', CACHE_TEMPORARY, drupal_get_headers());
}
}
}
diff --git a/includes/form.inc b/includes/form.inc
index 007cc9f90..740a21d62 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -2476,7 +2476,7 @@ function form_clean_id($id = NULL, $flush = FALSE) {
* foreach ($results as $result) {
* $items[] = t('Loaded node %title.', array('%title' => $result));
* }
- * $_SESSION['my_batch_results'] = $items;
+ * drupal_set_session('my_batch_results', $items);
* }
* @endcode
*/
diff --git a/includes/session.inc b/includes/session.inc
index aae3f29ff..aa06db4ca 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -124,11 +124,10 @@ function _sess_read($key) {
function _sess_write($key, $value) {
global $user;
- // If saving of session data is disabled or if the client doesn't have a session,
- // and one isn't being created ($value), do nothing. This keeps crawlers out of
- // the session table. This reduces memory and server load, and gives more useful
- // statistics. We can't eliminate anonymous session table rows without breaking
- // the "Who's Online" block.
+ // If saving of session data is disabled, or if a new empty anonymous session
+ // has been started, do nothing. This keeps anonymous users, including
+ // crawlers, out of the session table, unless they actually have something
+ // stored in $_SESSION.
if (!drupal_save_session() || ($user->uid == 0 && empty($_COOKIE[session_name()]) && empty($value))) {
return TRUE;
}
@@ -159,6 +158,72 @@ function _sess_write($key, $value) {
}
/**
+ * Propagate $_SESSION and set session cookie if not already set. This function
+ * should be called before writing to $_SESSION, usually via
+ * drupal_set_session().
+ *
+ * @param $start
+ * If FALSE, the session is not actually started. This is only used by
+ * drupal_session_is_started().
+ * @return
+ * TRUE if session has already been started, or FALSE if it has not.
+ */
+function drupal_session_start($start = TRUE) {
+ static $started = FALSE;
+ if ($start && !$started) {
+ $started = TRUE;
+ session_start();
+ }
+ return $started;
+}
+
+/**
+ * Return whether a session has been started and the $_SESSION variable is
+ * available.
+ */
+function drupal_session_is_started() {
+ return drupal_session_start(FALSE);
+}
+
+/**
+ * Get a session variable.
+ *
+ * @param $name
+ * The name of the variable to get. If not supplied, all variables are returned.
+ * @return
+ * The value of the variable, or FALSE if the variable is not set.
+ */
+function drupal_get_session($name = NULL) {
+ if (is_null($name)) {
+ return $_SESSION;
+ }
+ elseif (isset($_SESSION[$name])) {
+ return $_SESSION[$name];
+ }
+ else {
+ return FALSE;
+ }
+}
+
+/**
+ * Set a session variable. The variable becomes accessible via $_SESSION[$name]
+ * in the current and later requests. If there is no active PHP session prior
+ * to the call, one is started automatically.
+ *
+ * Anonymous users generate less server load if their $_SESSION variable is
+ * empty, so unused entries should be unset using unset($_SESSION['foo']).
+ *
+ * @param $name
+ * The name of the variable to set.
+ * @param $value
+ * The value to set.
+ */
+function drupal_set_session($name, $value) {
+ drupal_session_start();
+ $_SESSION[$name] = $value;
+}
+
+/**
* Called when an anonymous user becomes authenticated or vice-versa.
*/
function drupal_session_regenerate() {
@@ -211,6 +276,9 @@ function _sess_destroy_sid($sid) {
db_delete('sessions')
->condition('sid', $sid)
->execute();
+ // Unset cookie.
+ extract(session_get_cookie_params());
+ setcookie(session_name(), '', time() - 3600, $path, $domain, $secure, $httponly);
}
/**