private $curIndex = 0;
/** @var WebRequest[] Session requests */
- private $requests = array();
+ private $requests = [];
/** @var SessionProvider provider */
private $provider;
!isset( $blob['metadata'] ) || !is_array( $blob['metadata'] ) ||
!isset( $blob['data'] ) || !is_array( $blob['data'] )
) {
- $this->data = array();
+ $this->data = [];
$this->dataDirty = true;
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" is unsaved, marking dirty in constructor',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
} else {
$this->data = $blob['data'];
if ( isset( $blob['metadata']['loggedOut'] ) ) {
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" metadata dirty due to missing expiration timestamp',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
}
}
$this->dataHash = md5( serialize( $this->data ) );
public function getSession( WebRequest $request ) {
$index = ++$this->curIndex;
$this->requests[$index] = $request;
- $session = new Session( $this, $index );
+ $session = new Session( $this, $index, $this->logger );
return $session;
}
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" metadata dirty due to ID reset (formerly "{oldId}")',
- array(
+ [
'session' => $this->id,
'oldId' => $oldId,
- ) );
+ ] );
if ( $restart ) {
session_id( (string)$this->id );
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" force-persist due to persist()',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
$this->autosave();
} else {
$this->renew();
}
}
+ /**
+ * Make this session not persisted across requests
+ */
+ public function unpersist() {
+ if ( $this->persist ) {
+ // Close the PHP session, if we're the one that's open
+ if ( $this->usePhpSessionHandling && PHPSessionHandler::isEnabled() &&
+ session_id() === (string)$this->id
+ ) {
+ $this->logger->debug(
+ 'SessionBackend "{session}" Closing PHP session for unpersist',
+ [ 'session' => $this->id ]
+ );
+ session_write_close();
+ session_id( '' );
+ }
+
+ $this->persist = false;
+ $this->forcePersist = true;
+ $this->metaDirty = true;
+
+ // Delete the session data, so the local cache-only write in
+ // self::save() doesn't get things out of sync with the backend.
+ $this->store->delete( wfMemcKey( 'MWSession', (string)$this->id ) );
+
+ $this->autosave();
+ }
+ }
+
/**
* Indicate whether the user should be remembered independently of the
* session ID.
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" metadata dirty due to remember-user change',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
$this->autosave();
}
}
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" metadata dirty due to user change',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
$this->autosave();
}
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" metadata dirty due to force-HTTPS change',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
$this->autosave();
}
}
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" metadata dirty due to logged-out-timestamp change',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
$this->autosave();
}
}
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{session}" metadata dirty due to provider metadata change',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
$this->autosave();
}
}
$this->dataDirty = true;
$this->logger->debug(
'SessionBackend "{session}" data dirty due to addData(): {callers}',
- array(
+ [
'session' => $this->id,
'callers' => wfGetAllCallers( 5 ),
- ) );
+ ] );
}
}
}
$this->dataDirty = true;
$this->logger->debug(
'SessionBackend "{session}" data dirty due to dirty(): {callers}',
- array(
+ [
'session' => $this->id,
'callers' => wfGetAllCallers( 5 ),
- ) );
+ ] );
}
/**
$this->metaDirty = true;
$this->logger->debug(
'SessionBackend "{callers}" metadata dirty for renew(): {callers}',
- array(
+ [
'session' => $this->id,
'callers' => wfGetAllCallers( 5 ),
- ) );
+ ] );
if ( $this->persist ) {
$this->forcePersist = true;
$this->logger->debug(
'SessionBackend "{session}" force-persist for renew(): {callers}',
- array(
+ [
'session' => $this->id,
'callers' => wfGetAllCallers( 5 ),
- ) );
+ ] );
}
}
$this->autosave();
* @return \ScopedCallback When this goes out of scope, a save will be triggered
*/
public function delaySave() {
- $that = $this;
$this->delaySave++;
- $ref = &$this->delaySave;
- return new \ScopedCallback( function () use ( $that, &$ref ) {
- if ( --$ref <= 0 ) {
- $ref = 0;
- $that->save();
+ return new \ScopedCallback( function () {
+ if ( --$this->delaySave <= 0 ) {
+ $this->delaySave = 0;
+ $this->save();
}
} );
}
* @param bool $closing Whether the session is being closed
*/
public function save( $closing = false ) {
- if ( $this->provider->getManager()->isUserSessionPrevented( $this->user->getName() ) ) {
+ $anon = $this->user->isAnon();
+
+ if ( !$anon && $this->provider->getManager()->isUserSessionPrevented( $this->user->getName() ) ) {
$this->logger->debug(
'SessionBackend "{session}" not saving, user {user} was ' .
'passed to SessionManager::preventSessionsForUser',
- array(
+ [
'session' => $this->id,
'user' => $this->user,
- ) );
+ ] );
return;
}
// Ensure the user has a token
// @codeCoverageIgnoreStart
- $anon = $this->user->isAnon();
if ( !$anon && !$this->user->getToken( false ) ) {
$this->logger->debug(
'SessionBackend "{session}" creating token for user {user} on save',
- array(
+ [
'session' => $this->id,
'user' => $this->user,
- ) );
+ ] );
$this->user->setToken();
if ( !wfReadOnly() ) {
$this->user->saveSettings();
) {
$this->logger->debug(
'SessionBackend "{session}" data dirty due to hash mismatch, {expected} !== {got}',
- array(
+ [
'session' => $this->id,
'expected' => $this->dataHash,
'got' => md5( serialize( $this->data ) ),
- ) );
+ ] );
$this->dataDirty = true;
}
$this->logger->debug(
'SessionBackend "{session}" save: dataDirty={dataDirty} ' .
'metaDirty={metaDirty} forcePersist={forcePersist}',
- array(
+ [
'session' => $this->id,
'dataDirty' => (int)$this->dataDirty,
'metaDirty' => (int)$this->metaDirty,
'forcePersist' => (int)$this->forcePersist,
- ) );
+ ] );
- // Persist to the provider, if flagged
- if ( $this->persist && ( $this->metaDirty || $this->forcePersist ) ) {
- foreach ( $this->requests as $request ) {
- $request->setSessionId( $this->getSessionId() );
- $this->provider->persistSession( $this, $request );
- }
- if ( !$closing ) {
- $this->checkPHPSession();
+ // Persist or unpersist to the provider, if necessary
+ if ( $this->metaDirty || $this->forcePersist ) {
+ if ( $this->persist ) {
+ foreach ( $this->requests as $request ) {
+ $request->setSessionId( $this->getSessionId() );
+ $this->provider->persistSession( $this, $request );
+ }
+ if ( !$closing ) {
+ $this->checkPHPSession();
+ }
+ } else {
+ foreach ( $this->requests as $request ) {
+ if ( $request->getSessionId() === $this->id ) {
+ $this->provider->unpersistSession( $request );
+ }
+ }
}
}
}
// Save session data to store, if necessary
- $metadata = $origMetadata = array(
+ $metadata = $origMetadata = [
'provider' => (string)$this->provider,
'providerMetadata' => $this->providerMetadata,
'userId' => $anon ? 0 : $this->user->getId(),
'expires' => time() + $this->lifetime,
'loggedOut' => $this->loggedOut,
'persisted' => $this->persist,
- );
+ ];
- \Hooks::run( 'SessionMetadata', array( $this, &$metadata, $this->requests ) );
+ \Hooks::run( 'SessionMetadata', [ $this, &$metadata, $this->requests ] );
foreach ( $origMetadata as $k => $v ) {
if ( $metadata[$k] !== $v ) {
$this->store->set(
wfMemcKey( 'MWSession', (string)$this->id ),
- array(
+ [
'data' => $this->data,
'metadata' => $metadata,
- ),
+ ],
$metadata['expires'],
$this->persist ? 0 : CachedBagOStuff::WRITE_CACHE_ONLY
);
private function checkPHPSession() {
if ( !$this->checkPHPSessionRecursionGuard ) {
$this->checkPHPSessionRecursionGuard = true;
- $ref = &$this->checkPHPSessionRecursionGuard;
- $reset = new \ScopedCallback( function () use ( &$ref ) {
- $ref = false;
+ $reset = new \ScopedCallback( function () {
+ $this->checkPHPSessionRecursionGuard = false;
} );
if ( $this->usePhpSessionHandling && session_id() === '' && PHPSessionHandler::isEnabled() &&
) {
$this->logger->debug(
'SessionBackend "{session}" Taking over PHP session',
- array(
+ [
'session' => $this->id,
- ) );
+ ] );
session_id( (string)$this->id );
\MediaWiki\quietCall( 'session_start' );
}