From 08aa4418c30cfc18ccc69a0f0f9cb9e17be6c196 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Mon, 12 Aug 2013 09:28:15 +0200 Subject: Update to MediaWiki 1.21.1 --- includes/context/ContextSource.php | 22 ++++-- includes/context/DerivativeContext.php | 24 +++--- includes/context/IContextSource.php | 15 +++- includes/context/RequestContext.php | 137 ++++++++++++++++++++++++++++----- 4 files changed, 154 insertions(+), 44 deletions(-) (limited to 'includes/context') diff --git a/includes/context/ContextSource.php b/includes/context/ContextSource.php index 45bd6fff..33f51cb9 100644 --- a/includes/context/ContextSource.php +++ b/includes/context/ContextSource.php @@ -28,7 +28,6 @@ * member variable and provide accessors to it. */ abstract class ContextSource implements IContextSource { - /** * @var IContextSource */ @@ -42,7 +41,7 @@ abstract class ContextSource implements IContextSource { public function getContext() { if ( $this->context === null ) { $class = get_class( $this ); - wfDebug( __METHOD__ . " ($class): called and \$context is null. Using RequestContext::getMain() for sanity\n" ); + wfDebug( __METHOD__ . " ($class): called and \$context is null. Using RequestContext::getMain() for sanity\n" ); $this->context = RequestContext::getMain(); } return $this->context; @@ -52,7 +51,7 @@ abstract class ContextSource implements IContextSource { * Set the IContextSource object * * @since 1.18 - * @param $context IContextSource + * @param IContextSource $context */ public function setContext( IContextSource $context ) { $this->context = $context; @@ -107,7 +106,7 @@ abstract class ContextSource implements IContextSource { * Get the OutputPage object * * @since 1.18 - * @return OutputPage object + * @return OutputPage */ public function getOutput() { return $this->getContext()->getOutput(); @@ -159,12 +158,21 @@ abstract class ContextSource implements IContextSource { * Parameters are the same as wfMessage() * * @since 1.18 - * @return Message object + * @return Message */ public function msg( /* $args */ ) { $args = func_get_args(); return call_user_func_array( array( $this->getContext(), 'msg' ), $args ); } - -} + /** + * Export the resolved user IP, HTTP headers, user ID, and session ID. + * The result will be reasonably sized to allow for serialization. + * + * @return Array + * @since 1.21 + */ + public function exportSession() { + return $this->getContext()->exportSession(); + } +} diff --git a/includes/context/DerivativeContext.php b/includes/context/DerivativeContext.php index 5adf3621..b9a70068 100644 --- a/includes/context/DerivativeContext.php +++ b/includes/context/DerivativeContext.php @@ -30,7 +30,6 @@ * a different Title instance set on it. */ class DerivativeContext extends ContextSource { - /** * @var WebRequest */ @@ -68,7 +67,7 @@ class DerivativeContext extends ContextSource { /** * Constructor - * @param $context IContextSource Context to inherit from + * @param IContextSource $context Context to inherit from */ public function __construct( IContextSource $context ) { $this->setContext( $context ); @@ -77,7 +76,7 @@ class DerivativeContext extends ContextSource { /** * Set the WebRequest object * - * @param $r WebRequest object + * @param WebRequest $r */ public function setRequest( WebRequest $r ) { $this->request = $r; @@ -99,7 +98,7 @@ class DerivativeContext extends ContextSource { /** * Set the Title object * - * @param $t Title object + * @param Title $t */ public function setTitle( Title $t ) { $this->title = $t; @@ -140,7 +139,7 @@ class DerivativeContext extends ContextSource { * Set the WikiPage object * * @since 1.19 - * @param $p WikiPage object + * @param WikiPage $p */ public function setWikiPage( WikiPage $p ) { $this->wikipage = $p; @@ -166,7 +165,7 @@ class DerivativeContext extends ContextSource { /** * Set the OutputPage object * - * @param $o OutputPage + * @param OutputPage $o */ public function setOutput( OutputPage $o ) { $this->output = $o; @@ -175,7 +174,7 @@ class DerivativeContext extends ContextSource { /** * Get the OutputPage object * - * @return OutputPage object + * @return OutputPage */ public function getOutput() { if ( !is_null( $this->output ) ) { @@ -188,7 +187,7 @@ class DerivativeContext extends ContextSource { /** * Set the User object * - * @param $u User + * @param User $u */ public function setUser( User $u ) { $this->user = $u; @@ -211,7 +210,7 @@ class DerivativeContext extends ContextSource { * Set the Language object * * @deprecated 1.19 Use setLanguage instead - * @param $l Mixed Language instance or language code + * @param Language|string $l Language instance or language code */ public function setLang( $l ) { wfDeprecated( __METHOD__, '1.19' ); @@ -221,7 +220,8 @@ class DerivativeContext extends ContextSource { /** * Set the Language object * - * @param $l Mixed Language instance or language code + * @param Language|string $l Language instance or language code + * @throws MWException * @since 1.19 */ public function setLanguage( $l ) { @@ -262,7 +262,7 @@ class DerivativeContext extends ContextSource { /** * Set the Skin object * - * @param $s Skin + * @param Skin $s */ public function setSkin( Skin $s ) { $this->skin = clone $s; @@ -281,6 +281,4 @@ class DerivativeContext extends ContextSource { return $this->getContext()->getSkin(); } } - } - diff --git a/includes/context/IContextSource.php b/includes/context/IContextSource.php index 476035b5..c7b221b9 100644 --- a/includes/context/IContextSource.php +++ b/includes/context/IContextSource.php @@ -27,7 +27,6 @@ * Interface for objects which can provide a context on request. */ interface IContextSource { - /** * Get the WebRequest object * @@ -66,7 +65,7 @@ interface IContextSource { /** * Get the OutputPage object * - * @return OutputPage object + * @return OutputPage */ public function getOutput(); @@ -103,8 +102,16 @@ interface IContextSource { /** * Get a Message object with context set * - * @return Message object + * @return Message */ public function msg(); -} + /** + * Export the resolved user IP, HTTP headers, user ID, and session ID. + * The result will be reasonably sized to allow for serialization. + * + * @return Array + * @since 1.21 + */ + public function exportSession(); +} diff --git a/includes/context/RequestContext.php b/includes/context/RequestContext.php index 9e7837d9..6aefc98e 100644 --- a/includes/context/RequestContext.php +++ b/includes/context/RequestContext.php @@ -28,7 +28,6 @@ * Group all the pieces relevant to the context of a request into one instance */ class RequestContext implements IContextSource { - /** * @var WebRequest */ @@ -67,7 +66,7 @@ class RequestContext implements IContextSource { /** * Set the WebRequest object * - * @param $r WebRequest object + * @param WebRequest $r */ public function setRequest( WebRequest $r ) { $this->request = $r; @@ -89,10 +88,12 @@ class RequestContext implements IContextSource { /** * Set the Title object * - * @param $t Title object + * @param Title $t */ public function setTitle( Title $t ) { $this->title = $t; + // Erase the WikiPage so a new one with the new title gets created. + $this->wikipage = null; } /** @@ -135,9 +136,15 @@ class RequestContext implements IContextSource { * Set the WikiPage object * * @since 1.19 - * @param $p WikiPage object + * @param WikiPage $p */ public function setWikiPage( WikiPage $p ) { + $contextTitle = $this->getTitle(); + $pageTitle = $p->getTitle(); + if ( !$contextTitle || !$pageTitle->equals( $contextTitle ) ) { + $this->setTitle( $pageTitle ); + } + // Defer this to the end since setTitle sets it to null. $this->wikipage = $p; } @@ -148,6 +155,7 @@ class RequestContext implements IContextSource { * canUseWikiPage() to check whether this method can be called safely. * * @since 1.19 + * @throws MWException * @return WikiPage */ public function getWikiPage() { @@ -171,7 +179,7 @@ class RequestContext implements IContextSource { /** * Get the OutputPage object * - * @return OutputPage object + * @return OutputPage */ public function getOutput() { if ( $this->output === null ) { @@ -183,7 +191,7 @@ class RequestContext implements IContextSource { /** * Set the User object * - * @param $u User + * @param User $u */ public function setUser( User $u ) { $this->user = $u; @@ -204,7 +212,7 @@ class RequestContext implements IContextSource { /** * Accepts a language code and ensures it's sane. Outputs a cleaned up language * code and replaces with $wgLanguageCode if not sane. - * @param $code string + * @param string $code Language code * @return string */ public static function sanitizeLangCode( $code ) { @@ -214,7 +222,7 @@ class RequestContext implements IContextSource { $code = strtolower( $code ); # Validate $code - if( empty( $code ) || !Language::isValidCode( $code ) || ( $code === 'qqq' ) ) { + if ( empty( $code ) || !Language::isValidCode( $code ) || ( $code === 'qqq' ) ) { wfDebug( "Invalid user language code\n" ); $code = $wgLanguageCode; } @@ -226,7 +234,7 @@ class RequestContext implements IContextSource { * Set the Language object * * @deprecated 1.19 Use setLanguage instead - * @param $l Mixed Language instance or language code + * @param Language|string $l Language instance or language code */ public function setLang( $l ) { wfDeprecated( __METHOD__, '1.19' ); @@ -236,7 +244,8 @@ class RequestContext implements IContextSource { /** * Set the Language object * - * @param $l Mixed Language instance or language code + * @param Language|string $l Language instance or language code + * @throws MWException * @since 1.19 */ public function setLanguage( $l ) { @@ -289,7 +298,7 @@ class RequestContext implements IContextSource { wfRunHooks( 'UserGetLanguageObject', array( $user, &$code, $this ) ); - if( $code === $wgLanguageCode ) { + if ( $code === $wgLanguageCode ) { $this->lang = $wgContLang; } else { $obj = Language::factory( $code ); @@ -305,7 +314,7 @@ class RequestContext implements IContextSource { /** * Set the Skin object * - * @param $s Skin + * @param Skin $s */ public function setSkin( Skin $s ) { $this->skin = clone $s; @@ -320,14 +329,14 @@ class RequestContext implements IContextSource { public function getSkin() { if ( $this->skin === null ) { wfProfileIn( __METHOD__ . '-createskin' ); - + $skin = null; wfRunHooks( 'RequestContextCreateSkin', array( $this, &$skin ) ); // If the hook worked try to set a skin from it if ( $skin instanceof Skin ) { $this->skin = $skin; - } elseif ( is_string($skin) ) { + } elseif ( is_string( $skin ) ) { $this->skin = Skin::newFromKey( $skin ); } @@ -335,7 +344,7 @@ class RequestContext implements IContextSource { // then go through the normal processing to load a skin if ( $this->skin === null ) { global $wgHiddenPrefs; - if( !in_array( 'skin', $wgHiddenPrefs ) ) { + if ( !in_array( 'skin', $wgHiddenPrefs ) ) { # get the user skin $userSkin = $this->getUser()->getOption( 'skin' ); $userSkin = $this->getRequest()->getVal( 'useskin', $userSkin ); @@ -361,7 +370,7 @@ class RequestContext implements IContextSource { * Get a Message object with context set * Parameters are the same as wfMessage() * - * @return Message object + * @return Message */ public function msg() { $args = func_get_args(); @@ -373,7 +382,7 @@ class RequestContext implements IContextSource { /** * Get the RequestContext object associated with the main request * - * @return RequestContext object + * @return RequestContext */ public static function getMain() { static $instance = null; @@ -383,6 +392,96 @@ class RequestContext implements IContextSource { return $instance; } + /** + * Export the resolved user IP, HTTP headers, user ID, and session ID. + * The result will be reasonably sized to allow for serialization. + * + * @return Array + * @since 1.21 + */ + public function exportSession() { + return array( + 'ip' => $this->getRequest()->getIP(), + 'headers' => $this->getRequest()->getAllHeaders(), + 'sessionId' => session_id(), + 'userId' => $this->getUser()->getId() + ); + } + + /** + * Import the resolved user IP, HTTP headers, user ID, and session ID. + * This sets the current session and sets $wgUser and $wgRequest. + * Once the return value falls out of scope, the old context is restored. + * This function can only be called within CLI mode scripts. + * + * This will setup the session from the given ID. This is useful when + * background scripts inherit context when acting on behalf of a user. + * + * $param array $params Result of RequestContext::exportSession() + * @return ScopedCallback + * @throws MWException + * @since 1.21 + */ + public static function importScopedSession( array $params ) { + if ( PHP_SAPI !== 'cli' ) { + // Don't send random private cookies or turn $wgRequest into FauxRequest + throw new MWException( "Sessions can only be imported in cli mode." ); + } elseif ( !strlen( $params['sessionId'] ) ) { + throw new MWException( "No session ID was specified." ); + } + + if ( $params['userId'] ) { // logged-in user + $user = User::newFromId( $params['userId'] ); + if ( !$user ) { + throw new MWException( "No user with ID '{$params['userId']}'." ); + } + } elseif ( !IP::isValid( $params['ip'] ) ) { + throw new MWException( "Could not load user '{$params['ip']}'." ); + } else { // anon user + $user = User::newFromName( $params['ip'], false ); + } + + $importSessionFunction = function( User $user, array $params ) { + global $wgRequest, $wgUser; + + $context = RequestContext::getMain(); + // Commit and close any current session + session_write_close(); // persist + session_id( '' ); // detach + $_SESSION = array(); // clear in-memory array + // Remove any user IP or agent information + $context->setRequest( new FauxRequest() ); + $wgRequest = $context->getRequest(); // b/c + // Now that all private information is detached from the user, it should + // be safe to load the new user. If errors occur or an exception is thrown + // and caught (leaving the main context in a mixed state), there is no risk + // of the User object being attached to the wrong IP, headers, or session. + $context->setUser( $user ); + $wgUser = $context->getUser(); // b/c + if ( strlen( $params['sessionId'] ) ) { // don't make a new random ID + wfSetupSession( $params['sessionId'] ); // sets $_SESSION + } + $request = new FauxRequest( array(), false, $_SESSION ); + $request->setIP( $params['ip'] ); + foreach ( $params['headers'] as $name => $value ) { + $request->setHeader( $name, $value ); + } + // Set the current context to use the new WebRequest + $context->setRequest( $request ); + $wgRequest = $context->getRequest(); // b/c + }; + + // Stash the old session and load in the new one + $oUser = self::getMain()->getUser(); + $oParams = self::getMain()->exportSession(); + $importSessionFunction( $user, $params ); + + // Set callback to save and close the new session and reload the old one + return new ScopedCallback( function() use ( $importSessionFunction, $oUser, $oParams ) { + $importSessionFunction( $oUser, $oParams ); + } ); + } + /** * Create a new extraneous context. The context is filled with information * external to the current session. @@ -397,7 +496,7 @@ class RequestContext implements IContextSource { * @param WebRequest|array $request A WebRequest or data to use for a FauxRequest * @return RequestContext */ - public static function newExtraneousContext( Title $title, $request=array() ) { + public static function newExtraneousContext( Title $title, $request = array() ) { $context = new self; $context->setTitle( $title ); if ( $request instanceof WebRequest ) { @@ -408,6 +507,4 @@ class RequestContext implements IContextSource { $context->user = User::newFromName( '127.0.0.1', false ); return $context; } - } - -- cgit v1.2.2