diff options
Diffstat (limited to 'includes')
-rw-r--r-- | includes/batch.inc | 7 | ||||
-rw-r--r-- | includes/bootstrap.inc | 70 | ||||
-rw-r--r-- | includes/common.inc | 51 | ||||
-rw-r--r-- | includes/form.inc | 2 | ||||
-rw-r--r-- | includes/session.inc | 78 |
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); } /** |