Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
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
40use MediaWiki\Config\SiteConfiguration;
41use MediaWiki\Context\RequestContext;
42use MediaWiki\Debug\MWDebug;
43use MediaWiki\Deferred\DeferredUpdates;
44use MediaWiki\Exception\FatalError;
45use MediaWiki\Exception\HttpError;
46use MediaWiki\Exception\MWExceptionHandler;
47use MediaWiki\Exception\MWExceptionRenderer;
48use MediaWiki\HookContainer\HookRunner;
49use MediaWiki\Language\Language;
50use MediaWiki\Logger\LoggerFactory;
51use MediaWiki\MainConfigNames;
52use MediaWiki\MainConfigSchema;
53use MediaWiki\MediaWikiServices;
54use MediaWiki\Message\Message;
55use MediaWiki\Registration\ExtensionRegistry;
56use MediaWiki\Registration\MissingExtensionException;
57use MediaWiki\Request\HeaderCallback;
58use MediaWiki\Session\SessionManager;
59use MediaWiki\Settings\DynamicDefaultValues;
60use MediaWiki\Settings\LocalSettingsLoader;
61use MediaWiki\Settings\SettingsBuilder;
62use MediaWiki\Settings\Source\PhpSettingsSource;
63use MediaWiki\Settings\Source\ReflectionSchemaSource;
64use MediaWiki\Settings\WikiFarmSettingsLoader;
65use MediaWiki\StubObject\StubGlobalUser;
66use MediaWiki\StubObject\StubUserLang;
67use MediaWiki\Title\Title;
68use MediaWiki\User\User;
69use Psr\Log\LoggerInterface;
70use Wikimedia\Http\HttpStatus;
71use Wikimedia\RequestTimeout\RequestTimeout;
72use Wikimedia\Telemetry\SpanInterface;
73use 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)
83if ( !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.
90if ( !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.
103global $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 */
111require_once MW_INSTALL_PATH . '/includes/AutoLoader.php';
112require_once MW_INSTALL_PATH . '/includes/Defines.php';
113
114// Assert that composer dependencies were successfully loaded
115if ( !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
145if ( 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
154require_once MW_INSTALL_PATH . '/includes/GlobalFunctions.php';
155
156// Install callback for normalizing headers.
157HeaderCallback::register();
158
159// Tell HttpStatus to use HeaderCallback for reporting warnings when
160// attempting to set headers after the headers have already been sent.
161HttpStatus::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.
167mb_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';
188if ( !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}
196unset( $wgScopeTest );
197
198try {
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
229if ( $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
245if ( 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.
261require __DIR__ . '/SetupDynamicConfig.php';
262
263if ( defined( 'MW_AUTOLOAD_TEST_CLASSES' ) ) {
264    require_once __DIR__ . '/../tests/common/TestsAutoLoader.php';
265}
266
267// Start time limit
268if ( $wgRequestTimeLimit && MW_ENTRY_POINT !== 'cli' ) {
269    RequestTimeout::singleton()->setWallTimeLimit( $wgRequestTimeLimit );
270}
271
272/**
273 * Load queued extensions
274 */
275if ( defined( 'MW_AUTOLOAD_TEST_CLASSES' ) ) {
276    ExtensionRegistry::getInstance()->setLoadTestClassesAndNamespaces( true );
277}
278
279ExtensionRegistry::getInstance()->setSettingsBuilder( $wgSettings );
280ExtensionRegistry::getInstance()->loadFromQueue();
281// Don't let any other extensions load
282ExtensionRegistry::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 */
289if ( 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.
303if ( 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().
312putenv( "LC_ALL={$locale}" );
313unset( $locale );
314
315// Set PHP runtime to the desired timezone
316date_default_timezone_set( $wgLocaltimezone );
317
318MWDebug::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.
323MediaWikiServices::allowGlobalInstance();
324
325// Define a constant that indicates that the bootstrapping of the service locator
326// is complete.
327define( 'MW_SERVICE_BOOTSTRAP_COMPLETE', 1 );
328
329MWExceptionRenderer::setShowExceptionDetails( $wgShowExceptionDetails );
330if ( !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}
335Profiler::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.
340call_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.
368if ( $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.
380if ( $wgCanonicalServer === false ) {
381    $wgCanonicalServer = MediaWikiServices::getInstance()->getUrlUtils()->getCanonicalServer();
382}
383$wgVirtualRestConfig['global']['domain'] = $wgCanonicalServer;
384
385if ( $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)
392if ( !$wgEmergencyContact ) {
393    $wgEmergencyContact = 'wikiadmin@' . $wgServerName;
394}
395if ( !$wgPasswordSender ) {
396    $wgPasswordSender = 'apache@' . $wgServerName;
397}
398if ( !$wgNoReplyAddress ) {
399    $wgNoReplyAddress = $wgPasswordSender;
400}
401
402// Non-trivial expansion of: $wgSecureLogin
403// (due to calling wfWarn).
404if ( $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.
411if ( $wgTmpDirectory === false ) {
412    $wgTmpDirectory = wfTempDir();
413}
414
415if ( $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.
431wfMemoryLimit( $wgMemoryLimit );
432
433// Explicit globals, so this works with bootstrap.php
434global $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
440if ( $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.
479if ( MW_ENTRY_POINT === 'index' ) {
480    $wgRequest->interpolateTitle();
481}
482
483if ( !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
551global $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
559register_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
579global $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
585foreach ( $wgExtensionFunctions as $func ) {
586    $func();
587}
588unset( $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.
592if ( !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.
609if ( 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();
622if ( $settingsWarnings ) {
623    $logger = LoggerFactory::getInstance( 'Settings' );
624    foreach ( $settingsWarnings as $msg ) {
625        $logger->warning( $msg );
626    }
627    unset( $logger );
628}
629
630unset( $settingsWarnings );
631
632// Explicit globals, so this works with bootstrap.php
633global $wgFullyInitialised;
634$wgFullyInitialised = true;
635
636// T264370
637if ( !defined( 'MW_NO_SESSION' ) && MW_ENTRY_POINT !== 'cli' ) {
638    $manager = MediaWikiServices::getInstance()->getSessionManager();
639    if ( $manager instanceof SessionManager ) {
640        $manager->logPotentialSessionLeakage();
641    }
642}