Merge "Log multiple IPs using the same session or the same user account"
[lhc/web/wiklou.git] / includes / session / PHPSessionHandler.php
index 5344321..7d7e1cb 100644 (file)
@@ -28,13 +28,10 @@ use BagOStuff;
 
 /**
  * Adapter for PHP's session handling
- * @todo Once we drop support for PHP < 5.4, use SessionHandlerInterface
- *  (should just be a matter of adding "implements SessionHandlerInterface" and
- *  changing the session_set_save_handler() call).
  * @ingroup Session
  * @since 1.27
  */
-class PHPSessionHandler {
+class PHPSessionHandler implements \SessionHandlerInterface {
        /** @var PHPSessionHandler */
        protected static $instance = null;
 
@@ -123,23 +120,18 @@ class PHPSessionHandler {
                ini_set( 'session.use_cookies', 0 );
                ini_set( 'session.use_trans_sid', 0 );
 
+               // T124510: Disable automatic PHP session related cache headers.
+               // MediaWiki adds it's own headers and the default PHP behavior may
+               // set headers such as 'Pragma: no-cache' that cause problems with
+               // some user agents.
+               session_cache_limiter( '' );
+
                // Also set a sane serialization handler
                \Wikimedia\PhpSessionSerializer::setSerializeHandler();
 
-               session_set_save_handler(
-                       array( self::$instance, 'open' ),
-                       array( self::$instance, 'close' ),
-                       array( self::$instance, 'read' ),
-                       array( self::$instance, 'write' ),
-                       array( self::$instance, 'destroy' ),
-                       array( self::$instance, 'gc' )
-               );
-
-               // It's necessary to register a shutdown function to call session_write_close(),
-               // because by the time the request shutdown function for the session module is
-               // called, other needed objects may have already been destroyed. Shutdown functions
-               // registered this way are called before object destruction.
-               register_shutdown_function( array( self::$instance, 'handleShutdown' ) );
+               // Register this as the save handler, and register an appropriate
+               // shutdown function.
+               session_set_save_handler( self::$instance, true );
        }
 
        /**
@@ -241,8 +233,10 @@ class PHPSessionHandler {
                        // This can happen under normal circumstances, if the session exists but is
                        // invalid. Let's emit a log warning instead of a PHP warning.
                        $this->logger->warning(
-                               __METHOD__ . ": Session \"$id\" cannot be loaded, skipping write."
-                       );
+                               __METHOD__ . ': Session "{session}" cannot be loaded, skipping write.',
+                               array(
+                                       'session' => $id,
+                       ) );
                        return true;
                }
 
@@ -258,7 +252,7 @@ class PHPSessionHandler {
                $changed = false;
                $cache = isset( $this->sessionFieldCache[$id] ) ? $this->sessionFieldCache[$id] : array();
                foreach ( $data as $key => $value ) {
-                       if ( !isset( $cache[$key] ) ) {
+                       if ( !array_key_exists( $key, $cache ) ) {
                                if ( $session->exists( $key ) ) {
                                        // New in both, so ignore and log
                                        $this->logger->warning(
@@ -293,7 +287,7 @@ class PHPSessionHandler {
                // (but not if $_SESSION can't represent it at all)
                \Wikimedia\PhpSessionSerializer::setLogger( new \Psr\Log\NullLogger() );
                foreach ( $cache as $key => $value ) {
-                       if ( !isset( $data[$key] ) && $session->exists( $key ) &&
+                       if ( !array_key_exists( $key, $data ) && $session->exists( $key ) &&
                                \Wikimedia\PhpSessionSerializer::encode( array( $key => true ) )
                        ) {
                                if ( $cache[$key] === $session->get( $key ) ) {
@@ -360,18 +354,4 @@ class PHPSessionHandler {
                $this->store->deleteObjectsExpiringBefore( $before );
                return true;
        }
-
-       /**
-        * Shutdown function.
-        *
-        * See the comment inside self::install for rationale.
-        * @codeCoverageIgnore
-        * @private For internal use only
-        */
-       public function handleShutdown() {
-               if ( $this->enable ) {
-                       session_write_close();
-               }
-       }
-
 }