Merge "Improve how slashes are stripped from filenames"
[lhc/web/wiklou.git] / includes / session / SessionBackend.php
index 0424a2d..264e1ae 100644 (file)
@@ -31,7 +31,7 @@ use WebRequest;
 /**
  * This is the actual workhorse for Session.
  *
- * Most code does not need to use this class, you want \\MediaWiki\\Session\\Session.
+ * Most code does not need to use this class, you want \MediaWiki\Session\Session.
  * The exceptions are SessionProviders and SessionMetadata hook functions,
  * which get an instance of this class rather than Session.
  *
@@ -94,6 +94,8 @@ final class SessionBackend {
        private $usePhpSessionHandling = true;
        private $checkPHPSessionRecursionGuard = false;
 
+       private $shutdown = false;
+
        /**
         * @param SessionId $id Session ID object
         * @param SessionInfo $info Session info to populate from
@@ -176,17 +178,26 @@ final class SessionBackend {
 
        /**
         * Deregister a Session
-        * @private For use by \\MediaWiki\\Session\\Session::__destruct() only
+        * @private For use by \MediaWiki\Session\Session::__destruct() only
         * @param int $index
         */
        public function deregisterSession( $index ) {
                unset( $this->requests[$index] );
-               if ( !count( $this->requests ) ) {
+               if ( !$this->shutdown && !count( $this->requests ) ) {
                        $this->save( true );
                        $this->provider->getManager()->deregisterSessionBackend( $this );
                }
        }
 
+       /**
+        * Shut down a session
+        * @private For use by \MediaWiki\Session\SessionManager::shutdown() only
+        */
+       public function shutdown() {
+               $this->save( true );
+               $this->shutdown = true;
+       }
+
        /**
         * Returns the session ID.
         * @return string
@@ -283,6 +294,35 @@ final class SessionBackend {
                }
        }
 
+       /**
+        * 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.
@@ -469,7 +509,7 @@ final class SessionBackend {
         * Note the caller is responsible for calling $this->dirty() if anything in
         * the array is changed.
         *
-        * @private For use by \\MediaWiki\\Session\\Session only.
+        * @private For use by \MediaWiki\Session\Session only.
         * @return array
         */
        public function &getData() {
@@ -501,7 +541,7 @@ final class SessionBackend {
 
        /**
         * Mark data as dirty
-        * @private For use by \\MediaWiki\\Session\\Session only.
+        * @private For use by \MediaWiki\Session\Session only.
         */
        public function dirty() {
                $this->dataDirty = true;
@@ -629,14 +669,22 @@ final class SessionBackend {
                                '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 );
+                                       }
+                               }
                        }
                }