MediaWiki
REL1_23
|
00001 <?php 00030 class RequestContext implements IContextSource { 00034 private $request; 00035 00039 private $title; 00040 00044 private $wikipage; 00045 00049 private $output; 00050 00054 private $user; 00055 00059 private $lang; 00060 00064 private $skin; 00065 00069 private $config; 00070 00076 public function setConfig( Config $c ) { 00077 $this->config = $c; 00078 } 00079 00085 public function getConfig() { 00086 if ( $this->config === null ) { 00087 // @todo In the future, we could move this to WebStart.php so 00088 // the Config object is ready for when initialization happens 00089 $this->config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' ); 00090 } 00091 00092 return $this->config; 00093 } 00094 00100 public function setRequest( WebRequest $r ) { 00101 $this->request = $r; 00102 } 00103 00109 public function getRequest() { 00110 if ( $this->request === null ) { 00111 global $wgRequest; # fallback to $wg till we can improve this 00112 $this->request = $wgRequest; 00113 } 00114 00115 return $this->request; 00116 } 00117 00124 public function setTitle( $t ) { 00125 if ( $t !== null && !$t instanceof Title ) { 00126 throw new MWException( __METHOD__ . " expects an instance of Title" ); 00127 } 00128 $this->title = $t; 00129 // Erase the WikiPage so a new one with the new title gets created. 00130 $this->wikipage = null; 00131 } 00132 00138 public function getTitle() { 00139 if ( $this->title === null ) { 00140 global $wgTitle; # fallback to $wg till we can improve this 00141 $this->title = $wgTitle; 00142 } 00143 00144 return $this->title; 00145 } 00146 00155 public function canUseWikiPage() { 00156 if ( $this->wikipage !== null ) { 00157 # If there's a WikiPage object set, we can for sure get it 00158 return true; 00159 } 00160 $title = $this->getTitle(); 00161 if ( $title === null ) { 00162 # No Title, no WikiPage 00163 return false; 00164 } else { 00165 # Only namespaces whose pages are stored in the database can have WikiPage 00166 return $title->canExist(); 00167 } 00168 } 00169 00176 public function setWikiPage( WikiPage $p ) { 00177 $contextTitle = $this->getTitle(); 00178 $pageTitle = $p->getTitle(); 00179 if ( !$contextTitle || !$pageTitle->equals( $contextTitle ) ) { 00180 $this->setTitle( $pageTitle ); 00181 } 00182 // Defer this to the end since setTitle sets it to null. 00183 $this->wikipage = $p; 00184 } 00185 00196 public function getWikiPage() { 00197 if ( $this->wikipage === null ) { 00198 $title = $this->getTitle(); 00199 if ( $title === null ) { 00200 throw new MWException( __METHOD__ . ' called without Title object set' ); 00201 } 00202 $this->wikipage = WikiPage::factory( $title ); 00203 } 00204 00205 return $this->wikipage; 00206 } 00207 00211 public function setOutput( OutputPage $o ) { 00212 $this->output = $o; 00213 } 00214 00220 public function getOutput() { 00221 if ( $this->output === null ) { 00222 $this->output = new OutputPage( $this ); 00223 } 00224 00225 return $this->output; 00226 } 00227 00233 public function setUser( User $u ) { 00234 $this->user = $u; 00235 } 00236 00242 public function getUser() { 00243 if ( $this->user === null ) { 00244 $this->user = User::newFromSession( $this->getRequest() ); 00245 } 00246 00247 return $this->user; 00248 } 00249 00256 public static function sanitizeLangCode( $code ) { 00257 global $wgLanguageCode; 00258 00259 // BCP 47 - letter case MUST NOT carry meaning 00260 $code = strtolower( $code ); 00261 00262 # Validate $code 00263 if ( empty( $code ) || !Language::isValidCode( $code ) || ( $code === 'qqq' ) ) { 00264 wfDebug( "Invalid user language code\n" ); 00265 $code = $wgLanguageCode; 00266 } 00267 00268 return $code; 00269 } 00270 00277 public function setLang( $l ) { 00278 wfDeprecated( __METHOD__, '1.19' ); 00279 $this->setLanguage( $l ); 00280 } 00281 00289 public function setLanguage( $l ) { 00290 if ( $l instanceof Language ) { 00291 $this->lang = $l; 00292 } elseif ( is_string( $l ) ) { 00293 $l = self::sanitizeLangCode( $l ); 00294 $obj = Language::factory( $l ); 00295 $this->lang = $obj; 00296 } else { 00297 throw new MWException( __METHOD__ . " was passed an invalid type of data." ); 00298 } 00299 } 00300 00305 public function getLang() { 00306 wfDeprecated( __METHOD__, '1.19' ); 00307 00308 return $this->getLanguage(); 00309 } 00310 00318 public function getLanguage() { 00319 if ( isset( $this->recursion ) ) { 00320 trigger_error( "Recursion detected in " . __METHOD__, E_USER_WARNING ); 00321 $e = new Exception; 00322 wfDebugLog( 'recursion-guard', "Recursion detected:\n" . $e->getTraceAsString() ); 00323 00324 global $wgLanguageCode; 00325 $code = ( $wgLanguageCode ) ? $wgLanguageCode : 'en'; 00326 $this->lang = Language::factory( $code ); 00327 } elseif ( $this->lang === null ) { 00328 $this->recursion = true; 00329 00330 global $wgLanguageCode, $wgContLang; 00331 00332 $request = $this->getRequest(); 00333 $user = $this->getUser(); 00334 00335 $code = $request->getVal( 'uselang', $user->getOption( 'language' ) ); 00336 $code = self::sanitizeLangCode( $code ); 00337 00338 wfRunHooks( 'UserGetLanguageObject', array( $user, &$code, $this ) ); 00339 00340 if ( $code === $wgLanguageCode ) { 00341 $this->lang = $wgContLang; 00342 } else { 00343 $obj = Language::factory( $code ); 00344 $this->lang = $obj; 00345 } 00346 00347 unset( $this->recursion ); 00348 } 00349 00350 return $this->lang; 00351 } 00352 00358 public function setSkin( Skin $s ) { 00359 $this->skin = clone $s; 00360 $this->skin->setContext( $this ); 00361 } 00362 00368 public function getSkin() { 00369 if ( $this->skin === null ) { 00370 wfProfileIn( __METHOD__ . '-createskin' ); 00371 00372 $skin = null; 00373 wfRunHooks( 'RequestContextCreateSkin', array( $this, &$skin ) ); 00374 00375 // If the hook worked try to set a skin from it 00376 if ( $skin instanceof Skin ) { 00377 $this->skin = $skin; 00378 } elseif ( is_string( $skin ) ) { 00379 $this->skin = Skin::newFromKey( $skin ); 00380 } 00381 00382 // If this is still null (the hook didn't run or didn't work) 00383 // then go through the normal processing to load a skin 00384 if ( $this->skin === null ) { 00385 global $wgHiddenPrefs; 00386 if ( !in_array( 'skin', $wgHiddenPrefs ) ) { 00387 # get the user skin 00388 $userSkin = $this->getUser()->getOption( 'skin' ); 00389 $userSkin = $this->getRequest()->getVal( 'useskin', $userSkin ); 00390 } else { 00391 # if we're not allowing users to override, then use the default 00392 global $wgDefaultSkin; 00393 $userSkin = $wgDefaultSkin; 00394 } 00395 00396 $this->skin = Skin::newFromKey( $userSkin ); 00397 } 00398 00399 // After all that set a context on whatever skin got created 00400 $this->skin->setContext( $this ); 00401 wfProfileOut( __METHOD__ . '-createskin' ); 00402 } 00403 00404 return $this->skin; 00405 } 00406 00415 public function msg() { 00416 $args = func_get_args(); 00417 00418 return call_user_func_array( 'wfMessage', $args )->setContext( $this ); 00419 } 00420 00428 public static function getMain() { 00429 static $instance = null; 00430 if ( $instance === null ) { 00431 $instance = new self; 00432 } 00433 00434 return $instance; 00435 } 00436 00444 public function exportSession() { 00445 return array( 00446 'ip' => $this->getRequest()->getIP(), 00447 'headers' => $this->getRequest()->getAllHeaders(), 00448 'sessionId' => session_id(), 00449 'userId' => $this->getUser()->getId() 00450 ); 00451 } 00452 00469 public static function importScopedSession( array $params ) { 00470 if ( PHP_SAPI !== 'cli' ) { 00471 // Don't send random private cookies or turn $wgRequest into FauxRequest 00472 throw new MWException( "Sessions can only be imported in cli mode." ); 00473 } elseif ( !strlen( $params['sessionId'] ) ) { 00474 throw new MWException( "No session ID was specified." ); 00475 } 00476 00477 if ( $params['userId'] ) { // logged-in user 00478 $user = User::newFromId( $params['userId'] ); 00479 if ( !$user ) { 00480 throw new MWException( "No user with ID '{$params['userId']}'." ); 00481 } 00482 } elseif ( !IP::isValid( $params['ip'] ) ) { 00483 throw new MWException( "Could not load user '{$params['ip']}'." ); 00484 } else { // anon user 00485 $user = User::newFromName( $params['ip'], false ); 00486 } 00487 00488 $importSessionFunction = function ( User $user, array $params ) { 00489 global $wgRequest, $wgUser; 00490 00491 $context = RequestContext::getMain(); 00492 // Commit and close any current session 00493 session_write_close(); // persist 00494 session_id( '' ); // detach 00495 $_SESSION = array(); // clear in-memory array 00496 // Remove any user IP or agent information 00497 $context->setRequest( new FauxRequest() ); 00498 $wgRequest = $context->getRequest(); // b/c 00499 // Now that all private information is detached from the user, it should 00500 // be safe to load the new user. If errors occur or an exception is thrown 00501 // and caught (leaving the main context in a mixed state), there is no risk 00502 // of the User object being attached to the wrong IP, headers, or session. 00503 $context->setUser( $user ); 00504 $wgUser = $context->getUser(); // b/c 00505 if ( strlen( $params['sessionId'] ) ) { // don't make a new random ID 00506 wfSetupSession( $params['sessionId'] ); // sets $_SESSION 00507 } 00508 $request = new FauxRequest( array(), false, $_SESSION ); 00509 $request->setIP( $params['ip'] ); 00510 foreach ( $params['headers'] as $name => $value ) { 00511 $request->setHeader( $name, $value ); 00512 } 00513 // Set the current context to use the new WebRequest 00514 $context->setRequest( $request ); 00515 $wgRequest = $context->getRequest(); // b/c 00516 }; 00517 00518 // Stash the old session and load in the new one 00519 $oUser = self::getMain()->getUser(); 00520 $oParams = self::getMain()->exportSession(); 00521 $importSessionFunction( $user, $params ); 00522 00523 // Set callback to save and close the new session and reload the old one 00524 return new ScopedCallback( function () use ( $importSessionFunction, $oUser, $oParams ) { 00525 $importSessionFunction( $oUser, $oParams ); 00526 } ); 00527 } 00528 00543 public static function newExtraneousContext( Title $title, $request = array() ) { 00544 $context = new self; 00545 $context->setTitle( $title ); 00546 if ( $request instanceof WebRequest ) { 00547 $context->setRequest( $request ); 00548 } else { 00549 $context->setRequest( new FauxRequest( $request ) ); 00550 } 00551 $context->user = User::newFromName( '127.0.0.1', false ); 00552 00553 return $context; 00554 } 00555 }