Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 257 |
n/a |
0 / 0 |
CRAP | n/a |
0 / 0 |
||
| 1 | <?php |
| 2 | /** |
| 3 | * The setup for all MediaWiki processes (both web-based and CLI). |
| 4 | * |
| 5 | * The entry point (such as WebStart.php and doMaintenance.php) has these responsibilities: |
| 6 | * - The entry point MUST: |
| 7 | * - define the 'MEDIAWIKI' constant. |
| 8 | * - The entry point SHOULD: |
| 9 | * - define the 'MW_ENTRY_POINT' constant. |
| 10 | * - display an error if MW_CONFIG_CALLBACK is not defined and the |
| 11 | * file specified in MW_CONFIG_FILE (or the LocalSettings.php default location) |
| 12 | * does not exist. The error should either be sent before and instead |
| 13 | * of the Setup.php inclusion, or (if it needs classes and dependencies |
| 14 | * from core) the error can be displayed via a MW_CONFIG_CALLBACK, |
| 15 | * which must then abort the process to prevent the rest of Setup.php |
| 16 | * from executing. |
| 17 | * |
| 18 | * This file does: |
| 19 | * - run-time environment checks, |
| 20 | * - define MW_INSTALL_PATH, and $IP, |
| 21 | * - load autoloaders, constants, default settings, and global functions, |
| 22 | * - load the site configuration (e.g. LocalSettings.php), |
| 23 | * - load the enabled extensions (via ExtensionRegistry), |
| 24 | * - trivial expansion of site configuration defaults and shortcuts |
| 25 | * (no calls to MediaWikiServices or other parts of MediaWiki), |
| 26 | * - initialization of: |
| 27 | * - PHP run-time (setlocale, memory limit, default date timezone) |
| 28 | * - the debug logger (MWDebug) |
| 29 | * - the service container (MediaWikiServices) |
| 30 | * - the exception handler (MWExceptionHandler) |
| 31 | * - the session manager (SessionManager) |
| 32 | * - complex expansion of site configuration defaults (those that require |
| 33 | * calling into MediaWikiServices, global functions, or other classes.). |
| 34 | * |
| 35 | * @license GPL-2.0-or-later |
| 36 | * @file |
| 37 | */ |
| 38 | |
| 39 | // phpcs:disable MediaWiki.Usage.DeprecatedGlobalVariables |
| 40 | use MediaWiki\Config\SiteConfiguration; |
| 41 | use MediaWiki\Context\RequestContext; |
| 42 | use MediaWiki\Debug\MWDebug; |
| 43 | use MediaWiki\Deferred\DeferredUpdates; |
| 44 | use MediaWiki\Exception\FatalError; |
| 45 | use MediaWiki\Exception\HttpError; |
| 46 | use MediaWiki\Exception\MWExceptionHandler; |
| 47 | use MediaWiki\Exception\MWExceptionRenderer; |
| 48 | use MediaWiki\HookContainer\HookRunner; |
| 49 | use MediaWiki\Language\Language; |
| 50 | use MediaWiki\Logger\LoggerFactory; |
| 51 | use MediaWiki\MainConfigNames; |
| 52 | use MediaWiki\MainConfigSchema; |
| 53 | use MediaWiki\MediaWikiServices; |
| 54 | use MediaWiki\Message\Message; |
| 55 | use MediaWiki\Registration\ExtensionRegistry; |
| 56 | use MediaWiki\Registration\MissingExtensionException; |
| 57 | use MediaWiki\Request\HeaderCallback; |
| 58 | use MediaWiki\Session\SessionManager; |
| 59 | use MediaWiki\Settings\DynamicDefaultValues; |
| 60 | use MediaWiki\Settings\LocalSettingsLoader; |
| 61 | use MediaWiki\Settings\SettingsBuilder; |
| 62 | use MediaWiki\Settings\Source\PhpSettingsSource; |
| 63 | use MediaWiki\Settings\Source\ReflectionSchemaSource; |
| 64 | use MediaWiki\Settings\WikiFarmSettingsLoader; |
| 65 | use MediaWiki\StubObject\StubGlobalUser; |
| 66 | use MediaWiki\StubObject\StubUserLang; |
| 67 | use MediaWiki\Title\Title; |
| 68 | use MediaWiki\User\User; |
| 69 | use Psr\Log\LoggerInterface; |
| 70 | use Wikimedia\Http\HttpStatus; |
| 71 | use Wikimedia\RequestTimeout\RequestTimeout; |
| 72 | use Wikimedia\Telemetry\SpanInterface; |
| 73 | use Wikimedia\Telemetry\TracerState; |
| 74 | |
| 75 | /** |
| 76 | * Environment checks |
| 77 | * |
| 78 | * These are inline checks done before we include any source files, |
| 79 | * and thus these conditions may be assumed by all source code. |
| 80 | */ |
| 81 | |
| 82 | // This file must be included from a valid entry point (e.g. WebStart.php, Maintenance.php) |
| 83 | if ( !defined( 'MEDIAWIKI' ) ) { |
| 84 | exit( 1 ); |
| 85 | } |
| 86 | |
| 87 | // The MW_ENTRY_POINT constant must always exists, to make it safe to access. |
| 88 | // For compat, we do support older and custom MW entrypoints that don't set this, |
| 89 | // in which case we assign a default here. |
| 90 | if ( !defined( 'MW_ENTRY_POINT' ) ) { |
| 91 | /** |
| 92 | * The entry point, which may be either the script filename without the |
| 93 | * file extension, or "cli" for maintenance scripts, or "unknown" for any |
| 94 | * entry point that does not set the constant. |
| 95 | */ |
| 96 | define( 'MW_ENTRY_POINT', 'unknown' ); |
| 97 | } |
| 98 | |
| 99 | // The $IP variable is defined for use by LocalSettings.php. |
| 100 | // It is made available as a global variable for backwards compatibility. |
| 101 | // |
| 102 | // Source code should use the MW_INSTALL_PATH constant instead. |
| 103 | global $IP; |
| 104 | $IP = wfDetectInstallPath(); // ensures MW_INSTALL_PATH is defined |
| 105 | |
| 106 | /** |
| 107 | * Pre-config setup: Before loading LocalSettings.php |
| 108 | * |
| 109 | * These are changes and additions to runtime that don't vary on site configuration. |
| 110 | */ |
| 111 | require_once MW_INSTALL_PATH . '/includes/AutoLoader.php'; |
| 112 | require_once MW_INSTALL_PATH . '/includes/Defines.php'; |
| 113 | |
| 114 | // Assert that composer dependencies were successfully loaded |
| 115 | if ( !interface_exists( LoggerInterface::class ) ) { |
| 116 | $message = ( |
| 117 | '<strong>Error: Missing external libraries.</strong> ' . |
| 118 | 'MediaWiki depends on external libraries bundled with most MediaWiki distributions. ' . |
| 119 | "When installing MediaWiki from its Git reposistory, these must be installed separately.\n\n" . |
| 120 | 'Please see the <a href="https://www.mediawiki.org/wiki/Download_from_Git' . |
| 121 | '#Fetch_external_libraries">instructions for installing libraries</a> on mediawiki.org ' . |
| 122 | 'for help on installing the required libraries.' |
| 123 | ); |
| 124 | http_response_code( 500 ); |
| 125 | echo $message; |
| 126 | error_log( $message ); |
| 127 | exit( 1 ); |
| 128 | } |
| 129 | |
| 130 | // Deprecated global variable for backwards-compatibility. |
| 131 | // New code should check MW_ENTRY_POINT directly. |
| 132 | $wgCommandLineMode = MW_ENTRY_POINT === 'cli'; |
| 133 | |
| 134 | /** |
| 135 | * $wgConf hold the site configuration. |
| 136 | * Not used for much in a default install. |
| 137 | * @since 1.5 |
| 138 | */ |
| 139 | $wgConf = new SiteConfiguration; |
| 140 | |
| 141 | $wgAutoloadClasses ??= []; |
| 142 | |
| 143 | $wgSettings = SettingsBuilder::getInstance(); |
| 144 | |
| 145 | if ( defined( 'MW_USE_CONFIG_SCHEMA_CLASS' ) ) { |
| 146 | // Load config schema from MainConfigSchema. Useful for running scripts that |
| 147 | // generate other representations of the config schema. This is slow, so it |
| 148 | // should not be used for serving web traffic. |
| 149 | $wgSettings->load( new ReflectionSchemaSource( MainConfigSchema::class ) ); |
| 150 | } else { |
| 151 | $wgSettings->load( new PhpSettingsSource( MW_INSTALL_PATH . '/includes/config-schema.php' ) ); |
| 152 | } |
| 153 | |
| 154 | require_once MW_INSTALL_PATH . '/includes/GlobalFunctions.php'; |
| 155 | |
| 156 | // Install callback for normalizing headers. |
| 157 | HeaderCallback::register(); |
| 158 | |
| 159 | // Tell HttpStatus to use HeaderCallback for reporting warnings when |
| 160 | // attempting to set headers after the headers have already been sent. |
| 161 | HttpStatus::registerHeadersSentCallback( |
| 162 | [ HeaderCallback::class, 'warnIfHeadersSent' ] |
| 163 | ); |
| 164 | |
| 165 | // Set the encoding used by PHP for reading HTTP input, and writing output. |
| 166 | // This is also the default for mbstring functions. |
| 167 | mb_internal_encoding( 'UTF-8' ); |
| 168 | |
| 169 | /** |
| 170 | * Load LocalSettings.php |
| 171 | */ |
| 172 | |
| 173 | // Initialize some config settings with dynamic defaults, and |
| 174 | // make default settings available in globals for use in LocalSettings.php. |
| 175 | $wgSettings->putConfigValues( [ |
| 176 | MainConfigNames::ExtensionDirectory => MW_INSTALL_PATH . '/extensions', |
| 177 | MainConfigNames::StyleDirectory => MW_INSTALL_PATH . '/skins', |
| 178 | MainConfigNames::UploadDirectory => MW_INSTALL_PATH . '/images', |
| 179 | MainConfigNames::ServiceWiringFiles => [ MW_INSTALL_PATH . '/includes/ServiceWiring.php' ], |
| 180 | 'Version' => MW_VERSION, |
| 181 | ] ); |
| 182 | $wgSettings->apply(); |
| 183 | |
| 184 | // $wgSettings->apply() puts all configuration into global variables. |
| 185 | // If we are not in global scope, make all relevant globals available |
| 186 | // in this file's scope as well. |
| 187 | $wgScopeTest = 'MediaWiki Setup.php scope test'; |
| 188 | if ( !isset( $GLOBALS['wgScopeTest'] ) || $GLOBALS['wgScopeTest'] !== $wgScopeTest ) { |
| 189 | foreach ( $wgSettings->getConfigSchema()->getDefinedKeys() as $key ) { |
| 190 | $var = "wg$key"; |
| 191 | // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.allowedPrefix |
| 192 | global $$var; |
| 193 | } |
| 194 | unset( $key, $var ); |
| 195 | } |
| 196 | unset( $wgScopeTest ); |
| 197 | |
| 198 | try { |
| 199 | if ( defined( 'MW_CONFIG_CALLBACK' ) ) { |
| 200 | call_user_func( MW_CONFIG_CALLBACK, $wgSettings ); |
| 201 | } else { |
| 202 | wfDetectLocalSettingsFile( MW_INSTALL_PATH ); |
| 203 | |
| 204 | if ( getenv( 'MW_USE_LOCAL_SETTINGS_LOADER' ) ) { |
| 205 | // NOTE: This will not work for configuration variables that use a prefix |
| 206 | // other than "wg". |
| 207 | $localSettingsLoader = new LocalSettingsLoader( $wgSettings, MW_INSTALL_PATH ); |
| 208 | $localSettingsLoader->loadLocalSettingsFile( MW_CONFIG_FILE ); |
| 209 | unset( $localSettingsLoader ); |
| 210 | } else { |
| 211 | if ( str_ends_with( MW_CONFIG_FILE, '.php' ) ) { |
| 212 | // make defaults available as globals |
| 213 | $wgSettings->apply(); |
| 214 | require_once MW_CONFIG_FILE; |
| 215 | } else { |
| 216 | $wgSettings->loadFile( MW_CONFIG_FILE ); |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | // Make settings loaded by LocalSettings.php available in globals for use here |
| 222 | $wgSettings->apply(); |
| 223 | } catch ( MissingExtensionException $e ) { |
| 224 | // Make a common mistake give a friendly error |
| 225 | $e->render(); |
| 226 | } |
| 227 | |
| 228 | // If in a wiki-farm, load site-specific settings |
| 229 | if ( $wgSettings->getConfig()->get( MainConfigNames::WikiFarmSettingsDirectory ) ) { |
| 230 | $wikiFarmSettingsLoader = new WikiFarmSettingsLoader( $wgSettings ); |
| 231 | $wikiFarmSettingsLoader->loadWikiFarmSettings(); |
| 232 | unset( $wikiFarmSettingsLoader ); |
| 233 | } |
| 234 | |
| 235 | // All settings should be loaded now. |
| 236 | $wgSettings->enterRegistrationStage(); |
| 237 | |
| 238 | /** |
| 239 | * Customization point after most things are loaded (constants, functions, classes, |
| 240 | * LocalSettings. |
| 241 | * Note that this runs before extensions are registered, and before most singletons become |
| 242 | * available, and before MediaWikiServices is initialized. |
| 243 | */ |
| 244 | |
| 245 | if ( defined( 'MW_SETUP_CALLBACK' ) ) { |
| 246 | call_user_func( MW_SETUP_CALLBACK, $wgSettings ); |
| 247 | // Make any additional settings available in globals for use here |
| 248 | $wgSettings->apply(); |
| 249 | } |
| 250 | |
| 251 | // Apply dynamic defaults declared in config schema callbacks. |
| 252 | $dynamicDefaults = new DynamicDefaultValues( $wgSettings->getConfigSchema() ); |
| 253 | $dynamicDefaults->applyDynamicDefaults( $wgSettings->getConfigBuilder() ); |
| 254 | |
| 255 | // Make updated config available in global scope. |
| 256 | $wgSettings->apply(); |
| 257 | |
| 258 | // Apply dynamic defaults implemented in SetupDynamicConfig.php. |
| 259 | // Ideally, all logic in SetupDynamicConfig would be converted to |
| 260 | // callbacks in the config schema. |
| 261 | require __DIR__ . '/SetupDynamicConfig.php'; |
| 262 | |
| 263 | if ( defined( 'MW_AUTOLOAD_TEST_CLASSES' ) ) { |
| 264 | require_once __DIR__ . '/../tests/common/TestsAutoLoader.php'; |
| 265 | } |
| 266 | |
| 267 | // Start time limit |
| 268 | if ( $wgRequestTimeLimit && MW_ENTRY_POINT !== 'cli' ) { |
| 269 | RequestTimeout::singleton()->setWallTimeLimit( $wgRequestTimeLimit ); |
| 270 | } |
| 271 | |
| 272 | /** |
| 273 | * Load queued extensions |
| 274 | */ |
| 275 | if ( defined( 'MW_AUTOLOAD_TEST_CLASSES' ) ) { |
| 276 | ExtensionRegistry::getInstance()->setLoadTestClassesAndNamespaces( true ); |
| 277 | } |
| 278 | |
| 279 | ExtensionRegistry::getInstance()->setSettingsBuilder( $wgSettings ); |
| 280 | ExtensionRegistry::getInstance()->loadFromQueue(); |
| 281 | // Don't let any other extensions load |
| 282 | ExtensionRegistry::getInstance()->finish(); |
| 283 | |
| 284 | /** |
| 285 | * Customization point after ALL loading (constants, functions, classes, |
| 286 | * LocalSettings, extensions, dynamic defaults). |
| 287 | * Note that this runs before MediaWikiServices is initialized. |
| 288 | */ |
| 289 | if ( defined( 'MW_FINAL_SETUP_CALLBACK' ) ) { |
| 290 | call_user_func( MW_FINAL_SETUP_CALLBACK, $wgSettings ); |
| 291 | // Make any additional settings available in globals for use below |
| 292 | $wgSettings->apply(); |
| 293 | } |
| 294 | |
| 295 | // Config can no longer be changed. |
| 296 | $wgSettings->enterReadOnlyStage(); |
| 297 | |
| 298 | // Determine an appropriate locale (T291234) |
| 299 | // As of version 8, php no longer inherits the platform's locale so there |
| 300 | // shouldn't be a need to set a locale. However, setlocale is used to |
| 301 | // determine if the locale is available. macOS is avoided because setting |
| 302 | // it to C.UTF-8 changes pcre character classes on that platform. |
| 303 | if ( PHP_OS_FAMILY !== 'Darwin' && setlocale( LC_ALL, 'C.UTF-8' ) ) { |
| 304 | $locale = 'C.UTF-8'; |
| 305 | } else { |
| 306 | $locale = 'C'; |
| 307 | } |
| 308 | // The putenv() is meant to propagate the choice of locale to shell commands |
| 309 | // so that they will interpret UTF-8 correctly. If you have a problem with a |
| 310 | // shell command and need to send a special locale, you can override the locale |
| 311 | // with Command::environment(). |
| 312 | putenv( "LC_ALL={$locale}" ); |
| 313 | unset( $locale ); |
| 314 | |
| 315 | // Set PHP runtime to the desired timezone |
| 316 | date_default_timezone_set( $wgLocaltimezone ); |
| 317 | |
| 318 | MWDebug::setup(); |
| 319 | |
| 320 | // Enable the global service locator. |
| 321 | // Trivial expansion of site configuration should go before this point. |
| 322 | // Any non-trivial expansion that requires calling into MediaWikiServices or other parts of MW. |
| 323 | MediaWikiServices::allowGlobalInstance(); |
| 324 | |
| 325 | // Define a constant that indicates that the bootstrapping of the service locator |
| 326 | // is complete. |
| 327 | define( 'MW_SERVICE_BOOTSTRAP_COMPLETE', 1 ); |
| 328 | |
| 329 | MWExceptionRenderer::setShowExceptionDetails( $wgShowExceptionDetails ); |
| 330 | if ( !defined( 'MW_PHPUNIT_TEST' ) ) { |
| 331 | // Never install the handler in PHPUnit tests, otherwise PHPUnit's own handler will be unset and things |
| 332 | // like convertWarningsToExceptions won't work. |
| 333 | MWExceptionHandler::installHandler( $wgLogExceptionBacktrace, $wgPropagateErrors ); |
| 334 | } |
| 335 | Profiler::init( $wgProfiler ); |
| 336 | |
| 337 | // Initialize the root span for distributed tracing if we're in a web request context (T340552). |
| 338 | // Do this here since subsequent setup code, e.g. session initialization or post-setup hooks, |
| 339 | // may themselves create spans, so the root span needs to have been initialized by then. |
| 340 | call_user_func( static function (): void { |
| 341 | if ( wfIsCLI() ) { |
| 342 | return; |
| 343 | } |
| 344 | |
| 345 | $tracer = MediaWikiServices::getInstance()->getTracer(); |
| 346 | $request = RequestContext::getMain()->getRequest(); |
| 347 | // Backdate the start of the root span to the timestamp where PHP actually started working on this operation. |
| 348 | $startTimeNanos = (int)( 1e9 * $_SERVER['REQUEST_TIME_FLOAT'] ); |
| 349 | // Avoid high cardinality URL path as root span name, instead safely use the HTTP method. |
| 350 | // Per OTEL Semantic Conventions, https://opentelemetry.io/docs/specs/semconv/http/http-spans/ |
| 351 | $spanName = "EntryPoint " . MW_ENTRY_POINT . ".php HTTP {$request->getMethod()}"; |
| 352 | global $wgAllowExternalReqID; |
| 353 | $rootSpan = $tracer->createRootSpanFromCarrier( $spanName, $wgAllowExternalReqID ? $request->getAllHeaders() : [] ); |
| 354 | $rootSpan->setSpanKind( SpanInterface::SPAN_KIND_SERVER ) |
| 355 | ->setAttributes( array_filter( [ |
| 356 | 'http.request.method' => $request->getMethod(), |
| 357 | 'url.path' => $request->getRequestURL(), |
| 358 | 'server.name' => $_SERVER['SERVER_NAME'] ?? null, |
| 359 | ] ) ) |
| 360 | ->start( $startTimeNanos ); |
| 361 | $rootSpan->activate(); |
| 362 | |
| 363 | TracerState::getInstance()->setRootSpan( $rootSpan ); |
| 364 | } ); |
| 365 | |
| 366 | // Non-trivial validation of: $wgServer |
| 367 | // The FatalError page only renders cleanly after MWExceptionHandler is installed. |
| 368 | if ( $wgServer === false ) { |
| 369 | // T30798: $wgServer must be explicitly set |
| 370 | throw new FatalError( |
| 371 | '$wgServer must be set in LocalSettings.php. ' . |
| 372 | 'See <a href="https://www.mediawiki.org/wiki/Manual:$wgServer">' . |
| 373 | 'https://www.mediawiki.org/wiki/Manual:$wgServer</a>.' |
| 374 | ); |
| 375 | } |
| 376 | |
| 377 | // Non-trivial expansion of: $wgCanonicalServer, $wgServerName. |
| 378 | // These require calling global functions. |
| 379 | // Also here are other settings that further depend on these two. |
| 380 | if ( $wgCanonicalServer === false ) { |
| 381 | $wgCanonicalServer = MediaWikiServices::getInstance()->getUrlUtils()->getCanonicalServer(); |
| 382 | } |
| 383 | $wgVirtualRestConfig['global']['domain'] = $wgCanonicalServer; |
| 384 | |
| 385 | if ( $wgServerName !== false ) { |
| 386 | wfWarn( '$wgServerName should be derived from $wgCanonicalServer, ' |
| 387 | . 'not customized. Overwriting $wgServerName.' ); |
| 388 | } |
| 389 | $wgServerName = parse_url( $wgCanonicalServer, PHP_URL_HOST ); |
| 390 | |
| 391 | // $wgEmergencyContact and $wgPasswordSender may be false or empty string (T104142) |
| 392 | if ( !$wgEmergencyContact ) { |
| 393 | $wgEmergencyContact = 'wikiadmin@' . $wgServerName; |
| 394 | } |
| 395 | if ( !$wgPasswordSender ) { |
| 396 | $wgPasswordSender = 'apache@' . $wgServerName; |
| 397 | } |
| 398 | if ( !$wgNoReplyAddress ) { |
| 399 | $wgNoReplyAddress = $wgPasswordSender; |
| 400 | } |
| 401 | |
| 402 | // Non-trivial expansion of: $wgSecureLogin |
| 403 | // (due to calling wfWarn). |
| 404 | if ( $wgSecureLogin && !str_starts_with( $wgServer, '//' ) ) { |
| 405 | $wgSecureLogin = false; |
| 406 | wfWarn( 'Secure login was enabled on a server that only supports ' |
| 407 | . 'HTTP or HTTPS. Disabling secure login.' ); |
| 408 | } |
| 409 | |
| 410 | // Now that GlobalFunctions is loaded, set defaults that depend on it. |
| 411 | if ( $wgTmpDirectory === false ) { |
| 412 | $wgTmpDirectory = wfTempDir(); |
| 413 | } |
| 414 | |
| 415 | if ( $wgSharedDB && $wgSharedTables ) { |
| 416 | // Apply $wgSharedDB table aliases for the local LB (all non-foreign DB connections) |
| 417 | MediaWikiServices::getInstance()->getDBLoadBalancer()->setTableAliases( |
| 418 | array_fill_keys( |
| 419 | $wgSharedTables, |
| 420 | [ |
| 421 | 'dbname' => $wgSharedDB, |
| 422 | 'schema' => $wgSharedSchema, |
| 423 | 'prefix' => $wgSharedPrefix |
| 424 | ] |
| 425 | ) |
| 426 | ); |
| 427 | } |
| 428 | |
| 429 | // Raise the memory limit if it's too low |
| 430 | // NOTE: This use wfDebug, and must remain after the MWDebug::setup() call. |
| 431 | wfMemoryLimit( $wgMemoryLimit ); |
| 432 | |
| 433 | // Explicit globals, so this works with bootstrap.php |
| 434 | global $wgRequest; |
| 435 | |
| 436 | // Initialize the request object in $wgRequest |
| 437 | $wgRequest = RequestContext::getMain()->getRequest(); // BackCompat |
| 438 | |
| 439 | // Make sure that object caching does not undermine the ChronologyProtector improvements |
| 440 | if ( $wgRequest->getCookie( 'UseDC', '' ) === 'master' ) { |
| 441 | // The user is pinned to the primary DC, meaning that they made recent changes which should |
| 442 | // be reflected in their subsequent web requests. Avoid the use of interim cache keys because |
| 443 | // they use a blind TTL and could be stale if an object changes twice in a short time span. |
| 444 | MediaWikiServices::getInstance()->getMainWANObjectCache()->useInterimHoldOffCaching( false ); |
| 445 | } |
| 446 | |
| 447 | // Useful debug output |
| 448 | ( static function () { |
| 449 | global $wgRequest; |
| 450 | |
| 451 | $logger = LoggerFactory::getInstance( 'wfDebug' ); |
| 452 | if ( MW_ENTRY_POINT === 'cli' ) { |
| 453 | $self = $_SERVER['PHP_SELF'] ?? ''; |
| 454 | $logger->debug( "\n\nStart command line script $self" ); |
| 455 | } else { |
| 456 | $debug = "\n\nStart request {$wgRequest->getMethod()} {$wgRequest->getRequestURL()}\n"; |
| 457 | $debug .= "IP: " . $wgRequest->getIP() . "\n"; |
| 458 | $debug .= "HTTP HEADERS:\n"; |
| 459 | foreach ( $wgRequest->getAllHeaders() as $name => $value ) { |
| 460 | $debug .= "$name: $value\n"; |
| 461 | } |
| 462 | $debug .= "(end headers)"; |
| 463 | $logger->debug( $debug ); |
| 464 | } |
| 465 | } )(); |
| 466 | |
| 467 | // Most of the config is out, some might want to run hooks here. |
| 468 | ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onSetupAfterCache(); |
| 469 | |
| 470 | // Now that variant lists may be available, parse any action paths and article paths |
| 471 | // as query parameters. |
| 472 | // |
| 473 | // Skip title interpolation on API queries where it is useless and sometimes harmful (T18019). |
| 474 | // |
| 475 | // Optimization: Skip on load.php and all other entrypoints besides index.php to save time. |
| 476 | // |
| 477 | // TODO: Figure out if this can be safely done after everything else in Setup.php (e.g. any |
| 478 | // hooks or other state that would miss this?). If so, move to wfIndexMain or MediaWiki::run. |
| 479 | if ( MW_ENTRY_POINT === 'index' ) { |
| 480 | $wgRequest->interpolateTitle(); |
| 481 | } |
| 482 | |
| 483 | if ( !defined( 'MW_NO_SESSION' ) && MW_ENTRY_POINT !== 'cli' ) { |
| 484 | // If session.auto_start is there, we can't touch session name |
| 485 | if ( $wgPHPSessionHandling !== 'disable' && !wfIniGetBool( 'session.auto_start' ) ) { |
| 486 | HeaderCallback::warnIfHeadersSent(); |
| 487 | session_name( $wgSessionName ?: $wgCookiePrefix . '_session' ); |
| 488 | } |
| 489 | |
| 490 | // Create the SessionManager singleton and set up our session handler, |
| 491 | // unless we're specifically asked not to. |
| 492 | if ( !defined( 'MW_NO_SESSION_HANDLER' ) ) { |
| 493 | MediaWiki\Session\PHPSessionHandler::install( |
| 494 | MediaWikiServices::getInstance()->getSessionManager() |
| 495 | ); |
| 496 | // @phan-suppress-next-line PhanUndeclaredMethod shutdown() is not part of the public interface |
| 497 | register_shutdown_function( MediaWikiServices::getInstance()->getSessionManager()->shutdown( ... ) ); |
| 498 | } |
| 499 | |
| 500 | $contLang = MediaWikiServices::getInstance()->getContentLanguage(); |
| 501 | |
| 502 | // Initialize the session |
| 503 | try { |
| 504 | $session = RequestContext::getMain()->getRequest()->getSession(); |
| 505 | } catch ( MediaWiki\Session\SessionOverflowException $ex ) { |
| 506 | // The exception is because the request had multiple possible |
| 507 | // sessions tied for top priority. Report this to the user. |
| 508 | $list = []; |
| 509 | foreach ( $ex->getSessionInfos() as $info ) { |
| 510 | $list[] = $info->getProvider()->describe( $contLang ); |
| 511 | } |
| 512 | $list = $contLang->listToText( $list ); |
| 513 | throw new HttpError( 400, |
| 514 | Message::newFromKey( 'sessionmanager-tie', $list )->inLanguage( $contLang ) |
| 515 | ); |
| 516 | } |
| 517 | |
| 518 | unset( $contLang ); |
| 519 | |
| 520 | $session->renew(); |
| 521 | if ( MediaWiki\Session\PHPSessionHandler::isEnabled() && |
| 522 | ( $session->isPersistent() || $session->shouldRememberUser() ) && |
| 523 | session_id() !== $session->getId() |
| 524 | ) { |
| 525 | // Start the PHP-session for backwards compatibility |
| 526 | if ( session_id() !== '' ) { |
| 527 | wfDebugLog( 'session', 'PHP session {old_id} was already started, changing to {new_id}', 'all', [ |
| 528 | 'old_id' => session_id(), |
| 529 | 'new_id' => $session->getId(), |
| 530 | ] ); |
| 531 | session_write_close(); |
| 532 | } |
| 533 | session_id( $session->getId() ); |
| 534 | session_start(); |
| 535 | } |
| 536 | |
| 537 | unset( $session ); |
| 538 | } else { |
| 539 | // Even if we didn't set up a global Session, still install our session |
| 540 | // handler unless specifically requested not to. |
| 541 | if ( !defined( 'MW_NO_SESSION_HANDLER' ) ) { |
| 542 | MediaWiki\Session\PHPSessionHandler::install( |
| 543 | MediaWikiServices::getInstance()->getSessionManager() |
| 544 | ); |
| 545 | // @phan-suppress-next-line PhanUndeclaredMethod shutdown() is not part of the public interface |
| 546 | register_shutdown_function( MediaWikiServices::getInstance()->getSessionManager()->shutdown( ... ) ); |
| 547 | } |
| 548 | } |
| 549 | |
| 550 | // Explicit globals, so this works with bootstrap.php |
| 551 | global $wgUser, $wgLang, $wgOut, $wgTitle; |
| 552 | |
| 553 | /** |
| 554 | * @var User $wgUser |
| 555 | * @deprecated since 1.35, use an available context source when possible, or, as a backup, |
| 556 | * RequestContext::getMain() |
| 557 | */ |
| 558 | $wgUser = new StubGlobalUser( RequestContext::getMain()->getUser() ); // BackCompat |
| 559 | register_shutdown_function( static function () { |
| 560 | StubGlobalUser::$destructorDeprecationDisarmed = true; |
| 561 | } ); |
| 562 | |
| 563 | /** |
| 564 | * @var Language|StubUserLang $wgLang |
| 565 | */ |
| 566 | $wgLang = new StubUserLang; |
| 567 | |
| 568 | /** |
| 569 | * @var MediaWiki\Output\OutputPage $wgOut |
| 570 | */ |
| 571 | $wgOut = RequestContext::getMain()->getOutput(); // BackCompat |
| 572 | |
| 573 | /** |
| 574 | * @var Title|null $wgTitle |
| 575 | */ |
| 576 | $wgTitle = null; |
| 577 | |
| 578 | // Explicit globals, so this works with bootstrap.php |
| 579 | global $wgFullyInitialised, $wgExtensionFunctions; |
| 580 | |
| 581 | // Extension setup functions |
| 582 | // Entries should be added to this variable during the inclusion |
| 583 | // of the extension file. This allows the extension to perform |
| 584 | // any necessary initialisation in the fully initialised environment |
| 585 | foreach ( $wgExtensionFunctions as $func ) { |
| 586 | $func(); |
| 587 | } |
| 588 | unset( $func ); // no global pollution; destroy reference |
| 589 | |
| 590 | // If the session user has a 0 id but a valid name, that means we need to |
| 591 | // autocreate it. |
| 592 | if ( !defined( 'MW_NO_SESSION' ) && MW_ENTRY_POINT !== 'cli' ) { |
| 593 | $sessionUser = RequestContext::getMain()->getRequest()->getSession()->getUser(); |
| 594 | if ( $sessionUser->getId() === 0 && |
| 595 | MediaWikiServices::getInstance()->getUserNameUtils()->isValid( $sessionUser->getName() ) |
| 596 | ) { |
| 597 | MediaWikiServices::getInstance()->getAuthManager()->autoCreateUser( |
| 598 | $sessionUser, |
| 599 | MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION, |
| 600 | true, |
| 601 | true, |
| 602 | $sessionUser |
| 603 | ); |
| 604 | } |
| 605 | unset( $sessionUser ); |
| 606 | } |
| 607 | |
| 608 | // Optimization: Avoid overhead from DeferredUpdates and Pingback deps when turned off. |
| 609 | if ( MW_ENTRY_POINT !== 'cli' && $wgPingback ) { |
| 610 | // NOTE: Do not refactor to inject Config or otherwise make unconditional service call. |
| 611 | // |
| 612 | // On a plain install of MediaWiki, Pingback is likely the *only* feature |
| 613 | // involving DeferredUpdates or DB_PRIMARY on a regular page view. |
| 614 | // To allow for error recovery and fault isolation, let admins turn this |
| 615 | // off completely. (T269516) |
| 616 | DeferredUpdates::addCallableUpdate( static function () { |
| 617 | MediaWikiServices::getInstance()->getPingback()->run(); |
| 618 | } ); |
| 619 | } |
| 620 | |
| 621 | $settingsWarnings = $wgSettings->getWarnings(); |
| 622 | if ( $settingsWarnings ) { |
| 623 | $logger = LoggerFactory::getInstance( 'Settings' ); |
| 624 | foreach ( $settingsWarnings as $msg ) { |
| 625 | $logger->warning( $msg ); |
| 626 | } |
| 627 | unset( $logger ); |
| 628 | } |
| 629 | |
| 630 | unset( $settingsWarnings ); |
| 631 | |
| 632 | // Explicit globals, so this works with bootstrap.php |
| 633 | global $wgFullyInitialised; |
| 634 | $wgFullyInitialised = true; |
| 635 | |
| 636 | // T264370 |
| 637 | if ( !defined( 'MW_NO_SESSION' ) && MW_ENTRY_POINT !== 'cli' ) { |
| 638 | $manager = MediaWikiServices::getInstance()->getSessionManager(); |
| 639 | if ( $manager instanceof SessionManager ) { |
| 640 | $manager->logPotentialSessionLeakage(); |
| 641 | } |
| 642 | } |