242 lines
8.3 KiB
PHP
242 lines
8.3 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file
|
|
* User session handling functions.
|
|
*/
|
|
|
|
use Drupal\Component\Utility\Crypt;
|
|
use Drupal\Component\Utility\Settings;
|
|
use Drupal\Core\Session\AnonymousUserSession;
|
|
use Drupal\Core\Session\SessionHandler;
|
|
|
|
/**
|
|
* Initializes the session handler, starting a session if needed.
|
|
*/
|
|
function drupal_session_initialize() {
|
|
global $user;
|
|
|
|
// Register the default session handler.
|
|
// @todo: Extract session storage from session handler into a service.
|
|
$handler = new SessionHandler(\Drupal::request(), \Drupal::database());
|
|
session_set_save_handler($handler, TRUE);
|
|
|
|
$is_https = \Drupal::request()->isSecure();
|
|
$cookies = \Drupal::request()->cookies;
|
|
if (($cookies->has(session_name()) && ($session_name = $cookies->get(session_name()))) || ($is_https && Settings::get('mixed_mode_sessions', FALSE) && ($cookies->has(substr(session_name(), 1))) && ($session_name = $cookies->get(substr(session_name(), 1))))) {
|
|
// If a session cookie exists, initialize the session. Otherwise the
|
|
// session is only started on demand in drupal_session_commit(), making
|
|
// anonymous users not use a session cookie unless something is stored in
|
|
// $_SESSION. This allows HTTP proxies to cache anonymous pageviews.
|
|
drupal_session_start();
|
|
if ($user->isAuthenticated() || !empty($_SESSION)) {
|
|
drupal_page_is_cacheable(FALSE);
|
|
}
|
|
}
|
|
else {
|
|
// Set a session identifier for this request. This is necessary because
|
|
// we lazily start sessions at the end of this request, and some
|
|
// processes (like drupal_get_token()) needs to know the future
|
|
// session ID in advance.
|
|
$GLOBALS['lazy_session'] = TRUE;
|
|
$user = new AnonymousUserSession();
|
|
// Less random sessions (which are much faster to generate) are used for
|
|
// anonymous users than are generated in drupal_session_regenerate() when
|
|
// a user becomes authenticated.
|
|
session_id(Crypt::randomBytesBase64());
|
|
if ($is_https && Settings::get('mixed_mode_sessions', FALSE)) {
|
|
$insecure_session_name = substr(session_name(), 1);
|
|
$session_id = Crypt::randomBytesBase64();
|
|
$cookies->set($insecure_session_name, $session_id);
|
|
}
|
|
}
|
|
date_default_timezone_set(drupal_get_user_timezone());
|
|
}
|
|
|
|
/**
|
|
* Starts a session forcefully, preserving already set session data.
|
|
*
|
|
* @ingroup php_wrappers
|
|
*/
|
|
function drupal_session_start() {
|
|
// Command line clients do not support cookies nor sessions.
|
|
if (!drupal_session_started() && !drupal_is_cli()) {
|
|
// Save current session data before starting it, as PHP will destroy it.
|
|
$session_data = isset($_SESSION) ? $_SESSION : NULL;
|
|
|
|
session_start();
|
|
drupal_session_started(TRUE);
|
|
|
|
// Restore session data.
|
|
if (!empty($session_data)) {
|
|
$_SESSION += $session_data;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Commits the current session, if necessary.
|
|
*
|
|
* If an anonymous user already have an empty session, destroy it.
|
|
*/
|
|
function drupal_session_commit() {
|
|
global $user;
|
|
|
|
if (!drupal_save_session()) {
|
|
// We don't have anything to do if we are not allowed to save the session.
|
|
return;
|
|
}
|
|
|
|
if ($user->isAnonymous() && empty($_SESSION)) {
|
|
// There is no session data to store, destroy the session if it was
|
|
// previously started.
|
|
if (drupal_session_started()) {
|
|
session_destroy();
|
|
}
|
|
}
|
|
else {
|
|
// There is session data to store. Start the session if it is not already
|
|
// started.
|
|
if (!drupal_session_started()) {
|
|
drupal_session_start();
|
|
if (\Drupal::request()->isSecure() && Settings::get('mixed_mode_sessions', FALSE)) {
|
|
$insecure_session_name = substr(session_name(), 1);
|
|
$params = session_get_cookie_params();
|
|
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
|
|
$cookie_params = \Drupal::request()->cookies;
|
|
setcookie($insecure_session_name, $cookie_params->get($insecure_session_name), $expire, $params['path'], $params['domain'], FALSE, $params['httponly']);
|
|
}
|
|
}
|
|
// Write the session data.
|
|
session_write_close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether a session has been started.
|
|
*/
|
|
function drupal_session_started($set = NULL) {
|
|
static $session_started = FALSE;
|
|
if (isset($set)) {
|
|
$session_started = $set;
|
|
}
|
|
return $session_started && session_status() === \PHP_SESSION_ACTIVE;
|
|
}
|
|
|
|
/**
|
|
* Called when an anonymous user becomes authenticated or vice-versa.
|
|
*
|
|
* @ingroup php_wrappers
|
|
*/
|
|
function drupal_session_regenerate() {
|
|
global $user;
|
|
|
|
// Nothing to do if we are not allowed to change the session.
|
|
if (!drupal_save_session()) {
|
|
return;
|
|
}
|
|
|
|
$is_https = \Drupal::request()->isSecure();
|
|
$cookies = \Drupal::request()->cookies;
|
|
|
|
if ($is_https && Settings::get('mixed_mode_sessions', FALSE)) {
|
|
$insecure_session_name = substr(session_name(), 1);
|
|
if (!isset($GLOBALS['lazy_session']) && $cookies->has($insecure_session_name)) {
|
|
$old_insecure_session_id = $cookies->get($insecure_session_name);
|
|
}
|
|
$params = session_get_cookie_params();
|
|
$session_id = Crypt::randomBytesBase64();
|
|
// If a session cookie lifetime is set, the session will expire
|
|
// $params['lifetime'] seconds from the current request. If it is not set,
|
|
// it will expire when the browser is closed.
|
|
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
|
|
setcookie($insecure_session_name, $session_id, $expire, $params['path'], $params['domain'], FALSE, $params['httponly']);
|
|
$cookies->set($insecure_session_name, $session_id);
|
|
}
|
|
|
|
if (drupal_session_started()) {
|
|
$old_session_id = session_id();
|
|
}
|
|
session_id(Crypt::randomBytesBase64());
|
|
|
|
if (isset($old_session_id)) {
|
|
$params = session_get_cookie_params();
|
|
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
|
|
setcookie(session_name(), session_id(), $expire, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
|
$fields = array('sid' => Crypt::hashBase64(session_id()));
|
|
if ($is_https) {
|
|
$fields['ssid'] = Crypt::hashBase64(session_id());
|
|
// If the "secure pages" setting is enabled, use the newly-created
|
|
// insecure session identifier as the regenerated sid.
|
|
if (Settings::get('mixed_mode_sessions', FALSE)) {
|
|
$fields['sid'] = Crypt::hashBase64($session_id);
|
|
}
|
|
}
|
|
db_update('sessions')
|
|
->fields($fields)
|
|
->condition($is_https ? 'ssid' : 'sid', Crypt::hashBase64($old_session_id))
|
|
->execute();
|
|
}
|
|
elseif (isset($old_insecure_session_id)) {
|
|
// If logging in to the secure site, and there was no active session on the
|
|
// secure site but a session was active on the insecure site, update the
|
|
// insecure session with the new session identifiers.
|
|
db_update('sessions')
|
|
->fields(array('sid' => Crypt::hashBase64($session_id), 'ssid' => Crypt::hashBase64(session_id())))
|
|
->condition('sid', Crypt::hashBase64($old_insecure_session_id))
|
|
->execute();
|
|
}
|
|
else {
|
|
// Start the session when it doesn't exist yet.
|
|
// Preserve the logged in user, as it will be reset to anonymous
|
|
// by _drupal_session_read.
|
|
$account = $user;
|
|
drupal_session_start();
|
|
$user = $account;
|
|
}
|
|
date_default_timezone_set(drupal_get_user_timezone());
|
|
}
|
|
|
|
/**
|
|
* Ends a specific user's session(s).
|
|
*
|
|
* @param $uid
|
|
* User ID.
|
|
*/
|
|
function drupal_session_destroy_uid($uid) {
|
|
// Nothing to do if we are not allowed to change the session.
|
|
if (!drupal_save_session()) {
|
|
return;
|
|
}
|
|
|
|
db_delete('sessions')
|
|
->condition('uid', $uid)
|
|
->execute();
|
|
}
|
|
|
|
/**
|
|
* Determines whether to save session data of the current request.
|
|
*
|
|
* This function allows the caller to temporarily disable writing of
|
|
* session data, should the request end while performing potentially
|
|
* dangerous operations, such as manipulating the global $user object.
|
|
* See http://drupal.org/node/218104 for usage.
|
|
*
|
|
* @param $status
|
|
* Disables writing of session data when FALSE, (re-)enables
|
|
* writing when TRUE.
|
|
*
|
|
* @return
|
|
* FALSE if writing session data has been disabled. Otherwise, TRUE.
|
|
*/
|
|
function drupal_save_session($status = NULL) {
|
|
// PHP session ID, session, and cookie handling happens in the global scope.
|
|
// This value has to persist across calls to drupal_static_reset(), since a
|
|
// potentially wrong or disallowed session would be written otherwise.
|
|
static $save_session = TRUE;
|
|
if (isset($status)) {
|
|
$save_session = $status;
|
|
}
|
|
return $save_session;
|
|
}
|