Completed
Branch master (939199)
by
unknown
39:35
created

includes/Setup.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Include most things that are needed to make %MediaWiki work.
4
 *
5
 * This file is included by WebStart.php and doMaintenance.php so that both
6
 * web and maintenance scripts share a final set up phase to include necessary
7
 * files and create global object variables.
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License along
20
 * with this program; if not, write to the Free Software Foundation, Inc.,
21
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
 * http://www.gnu.org/copyleft/gpl.html
23
 *
24
 * @file
25
 */
26
use MediaWiki\MediaWikiServices;
27
28
/**
29
 * This file is not a valid entry point, perform no further processing unless
30
 * MEDIAWIKI is defined
31
 */
32
if ( !defined( 'MEDIAWIKI' ) ) {
33
	exit( 1 );
34
}
35
36
$fname = 'Setup.php';
37
$ps_setup = Profiler::instance()->scopedProfileIn( $fname );
38
39
// If any extensions are still queued, force load them
40
ExtensionRegistry::getInstance()->loadFromQueue();
41
42
// Check to see if we are at the file scope
43
if ( !isset( $wgVersion ) ) {
44
	echo "Error, Setup.php must be included from the file scope, after DefaultSettings.php\n";
45
	die( 1 );
46
}
47
48
mb_internal_encoding( 'UTF-8' );
49
50
// Set various default paths sensibly...
51
$ps_default = Profiler::instance()->scopedProfileIn( $fname . '-defaults' );
52
53
if ( $wgScript === false ) {
54
	$wgScript = "$wgScriptPath/index.php";
55
}
56
if ( $wgLoadScript === false ) {
57
	$wgLoadScript = "$wgScriptPath/load.php";
58
}
59
60
if ( $wgArticlePath === false ) {
61
	if ( $wgUsePathInfo ) {
62
		$wgArticlePath = "$wgScript/$1";
63
	} else {
64
		$wgArticlePath = "$wgScript?title=$1";
65
	}
66
}
67
68
if ( !empty( $wgActionPaths ) && !isset( $wgActionPaths['view'] ) ) {
69
	// 'view' is assumed the default action path everywhere in the code
70
	// but is rarely filled in $wgActionPaths
71
	$wgActionPaths['view'] = $wgArticlePath;
72
}
73
74
if ( $wgResourceBasePath === null ) {
75
	$wgResourceBasePath = $wgScriptPath;
76
}
77
if ( $wgStylePath === false ) {
78
	$wgStylePath = "$wgResourceBasePath/skins";
79
}
80
if ( $wgLocalStylePath === false ) {
81
	// Avoid wgResourceBasePath here since that may point to a different domain (e.g. CDN)
82
	$wgLocalStylePath = "$wgScriptPath/skins";
83
}
84
if ( $wgExtensionAssetsPath === false ) {
85
	$wgExtensionAssetsPath = "$wgResourceBasePath/extensions";
86
}
87
88
if ( $wgLogo === false ) {
89
	$wgLogo = "$wgResourceBasePath/resources/assets/wiki.png";
90
}
91
92
if ( $wgUploadPath === false ) {
93
	$wgUploadPath = "$wgScriptPath/images";
94
}
95
if ( $wgUploadDirectory === false ) {
96
	$wgUploadDirectory = "$IP/images";
97
}
98
if ( $wgReadOnlyFile === false ) {
99
	$wgReadOnlyFile = "{$wgUploadDirectory}/lock_yBgMBwiR";
100
}
101
if ( $wgFileCacheDirectory === false ) {
102
	$wgFileCacheDirectory = "{$wgUploadDirectory}/cache";
103
}
104
if ( $wgDeletedDirectory === false ) {
105
	$wgDeletedDirectory = "{$wgUploadDirectory}/deleted";
106
}
107
108
if ( $wgGitInfoCacheDirectory === false && $wgCacheDirectory !== false ) {
109
	$wgGitInfoCacheDirectory = "{$wgCacheDirectory}/gitinfo";
110
}
111
112
if ( $wgEnableParserCache === false ) {
113
	$wgParserCacheType = CACHE_NONE;
114
}
115
116
// Fix path to icon images after they were moved in 1.24
117
if ( $wgRightsIcon ) {
118
	$wgRightsIcon = str_replace(
119
		"{$wgStylePath}/common/images/",
120
		"{$wgResourceBasePath}/resources/assets/licenses/",
121
		$wgRightsIcon
122
	);
123
}
124
125
if ( isset( $wgFooterIcons['copyright']['copyright'] )
126
	&& $wgFooterIcons['copyright']['copyright'] === []
127
) {
128
	if ( $wgRightsIcon || $wgRightsText ) {
129
		$wgFooterIcons['copyright']['copyright'] = [
130
			'url' => $wgRightsUrl,
131
			'src' => $wgRightsIcon,
132
			'alt' => $wgRightsText,
133
		];
134
	}
135
}
136
137
if ( isset( $wgFooterIcons['poweredby'] )
138
	&& isset( $wgFooterIcons['poweredby']['mediawiki'] )
139
	&& $wgFooterIcons['poweredby']['mediawiki']['src'] === null
140
) {
141
	$wgFooterIcons['poweredby']['mediawiki']['src'] =
142
		"$wgResourceBasePath/resources/assets/poweredby_mediawiki_88x31.png";
143
	$wgFooterIcons['poweredby']['mediawiki']['srcset'] =
144
		"$wgResourceBasePath/resources/assets/poweredby_mediawiki_132x47.png 1.5x, " .
145
		"$wgResourceBasePath/resources/assets/poweredby_mediawiki_176x62.png 2x";
146
}
147
148
/**
149
 * Unconditional protection for NS_MEDIAWIKI since otherwise it's too easy for a
150
 * sysadmin to set $wgNamespaceProtection incorrectly and leave the wiki insecure.
151
 *
152
 * Note that this is the definition of editinterface and it can be granted to
153
 * all users if desired.
154
 */
155
$wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
156
157
/**
158
 * The canonical names of namespaces 6 and 7 are, as of v1.14, "File"
159
 * and "File_talk".  The old names "Image" and "Image_talk" are
160
 * retained as aliases for backwards compatibility.
161
 */
162
$wgNamespaceAliases['Image'] = NS_FILE;
163
$wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
164
165
/**
166
 * Initialise $wgLockManagers to include basic FS version
167
 */
168
$wgLockManagers[] = [
169
	'name' => 'fsLockManager',
170
	'class' => 'FSLockManager',
171
	'lockDirectory' => "{$wgUploadDirectory}/lockdir",
172
];
173
$wgLockManagers[] = [
174
	'name' => 'nullLockManager',
175
	'class' => 'NullLockManager',
176
];
177
178
/**
179
 * Initialise $wgLocalFileRepo from backwards-compatible settings
180
 */
181
if ( !$wgLocalFileRepo ) {
182
	$wgLocalFileRepo = [
183
		'class' => 'LocalRepo',
184
		'name' => 'local',
185
		'directory' => $wgUploadDirectory,
186
		'scriptDirUrl' => $wgScriptPath,
187
		'scriptExtension' => '.php',
188
		'url' => $wgUploadBaseUrl ? $wgUploadBaseUrl . $wgUploadPath : $wgUploadPath,
189
		'hashLevels' => $wgHashedUploadDirectory ? 2 : 0,
190
		'thumbScriptUrl' => $wgThumbnailScriptPath,
191
		'transformVia404' => !$wgGenerateThumbnailOnParse,
192
		'deletedDir' => $wgDeletedDirectory,
193
		'deletedHashLevels' => $wgHashedUploadDirectory ? 3 : 0
194
	];
195
}
196
/**
197
 * Initialise shared repo from backwards-compatible settings
198
 */
199
if ( $wgUseSharedUploads ) {
200
	if ( $wgSharedUploadDBname ) {
201
		$wgForeignFileRepos[] = [
202
			'class' => 'ForeignDBRepo',
203
			'name' => 'shared',
204
			'directory' => $wgSharedUploadDirectory,
205
			'url' => $wgSharedUploadPath,
206
			'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
207
			'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
208
			'transformVia404' => !$wgGenerateThumbnailOnParse,
209
			'dbType' => $wgDBtype,
210
			'dbServer' => $wgDBserver,
211
			'dbUser' => $wgDBuser,
212
			'dbPassword' => $wgDBpassword,
213
			'dbName' => $wgSharedUploadDBname,
214
			'dbFlags' => ( $wgDebugDumpSql ? DBO_DEBUG : 0 ) | DBO_DEFAULT,
215
			'tablePrefix' => $wgSharedUploadDBprefix,
216
			'hasSharedCache' => $wgCacheSharedUploads,
217
			'descBaseUrl' => $wgRepositoryBaseUrl,
218
			'fetchDescription' => $wgFetchCommonsDescriptions,
219
		];
220
	} else {
221
		$wgForeignFileRepos[] = [
222
			'class' => 'FileRepo',
223
			'name' => 'shared',
224
			'directory' => $wgSharedUploadDirectory,
225
			'url' => $wgSharedUploadPath,
226
			'hashLevels' => $wgHashedSharedUploadDirectory ? 2 : 0,
227
			'thumbScriptUrl' => $wgSharedThumbnailScriptPath,
228
			'transformVia404' => !$wgGenerateThumbnailOnParse,
229
			'descBaseUrl' => $wgRepositoryBaseUrl,
230
			'fetchDescription' => $wgFetchCommonsDescriptions,
231
		];
232
	}
233
}
234
if ( $wgUseInstantCommons ) {
235
	$wgForeignFileRepos[] = [
236
		'class' => 'ForeignAPIRepo',
237
		'name' => 'wikimediacommons',
238
		'apibase' => 'https://commons.wikimedia.org/w/api.php',
239
		'url' => 'https://upload.wikimedia.org/wikipedia/commons',
240
		'thumbUrl' => 'https://upload.wikimedia.org/wikipedia/commons/thumb',
241
		'hashLevels' => 2,
242
		'transformVia404' => true,
243
		'fetchDescription' => true,
244
		'descriptionCacheExpiry' => 43200,
245
		'apiThumbCacheExpiry' => 86400,
246
	];
247
}
248
/*
249
 * Add on default file backend config for file repos.
250
 * FileBackendGroup will handle initializing the backends.
251
 */
252
if ( !isset( $wgLocalFileRepo['backend'] ) ) {
253
	$wgLocalFileRepo['backend'] = $wgLocalFileRepo['name'] . '-backend';
254
}
255
foreach ( $wgForeignFileRepos as &$repo ) {
256
	if ( !isset( $repo['directory'] ) && $repo['class'] === 'ForeignAPIRepo' ) {
257
		$repo['directory'] = $wgUploadDirectory; // b/c
258
	}
259
	if ( !isset( $repo['backend'] ) ) {
260
		$repo['backend'] = $repo['name'] . '-backend';
261
	}
262
}
263
unset( $repo ); // no global pollution; destroy reference
264
265
$rcMaxAgeDays = $wgRCMaxAge / ( 3600 * 24 );
266
if ( $wgRCFilterByAge ) {
267
	// Trim down $wgRCLinkDays so that it only lists links which are valid
268
	// as determined by $wgRCMaxAge.
269
	// Note that we allow 1 link higher than the max for things like 56 days but a 60 day link.
270
	sort( $wgRCLinkDays );
271
272
	// @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
273
	for ( $i = 0; $i < count( $wgRCLinkDays ); $i++ ) {
274
		// @codingStandardsIgnoreEnd
275
		if ( $wgRCLinkDays[$i] >= $rcMaxAgeDays ) {
276
			$wgRCLinkDays = array_slice( $wgRCLinkDays, 0, $i + 1, false );
277
			break;
278
		}
279
	}
280
}
281
// Ensure that default user options are not invalid, since that breaks Special:Preferences
282
$wgDefaultUserOptions['rcdays'] = min(
283
	$wgDefaultUserOptions['rcdays'],
284
	ceil( $rcMaxAgeDays )
285
);
286
$wgDefaultUserOptions['watchlistdays'] = min(
287
	$wgDefaultUserOptions['watchlistdays'],
288
	ceil( $rcMaxAgeDays )
289
);
290
unset( $rcMaxAgeDays );
291
292
if ( $wgSkipSkin ) {
293
	$wgSkipSkins[] = $wgSkipSkin;
294
}
295
296
$wgSkipSkins[] = 'fallback';
297
$wgSkipSkins[] = 'apioutput';
298
299
if ( $wgLocalInterwiki ) {
300
	array_unshift( $wgLocalInterwikis, $wgLocalInterwiki );
301
}
302
303
// Set default shared prefix
304
if ( $wgSharedPrefix === false ) {
305
	$wgSharedPrefix = $wgDBprefix;
306
}
307
308
// Set default shared schema
309
if ( $wgSharedSchema === false ) {
310
	$wgSharedSchema = $wgDBmwschema;
311
}
312
313
if ( !$wgCookiePrefix ) {
314
	if ( $wgSharedDB && $wgSharedPrefix && in_array( 'user', $wgSharedTables ) ) {
315
		$wgCookiePrefix = $wgSharedDB . '_' . $wgSharedPrefix;
316
	} elseif ( $wgSharedDB && in_array( 'user', $wgSharedTables ) ) {
317
		$wgCookiePrefix = $wgSharedDB;
318
	} elseif ( $wgDBprefix ) {
319
		$wgCookiePrefix = $wgDBname . '_' . $wgDBprefix;
320
	} else {
321
		$wgCookiePrefix = $wgDBname;
322
	}
323
}
324
$wgCookiePrefix = strtr( $wgCookiePrefix, '=,; +."\'\\[', '__________' );
325
326
if ( $wgEnableEmail ) {
327
	$wgUseEnotif = $wgEnotifUserTalk || $wgEnotifWatchlist;
328
} else {
329
	// Disable all other email settings automatically if $wgEnableEmail
330
	// is set to false. - bug 63678
331
	$wgAllowHTMLEmail = false;
332
	$wgEmailAuthentication = false; // do not require auth if you're not sending email anyway
333
	$wgEnableUserEmail = false;
334
	$wgEnotifFromEditor = false;
335
	$wgEnotifImpersonal = false;
336
	$wgEnotifMaxRecips = 0;
337
	$wgEnotifMinorEdits = false;
338
	$wgEnotifRevealEditorAddress = false;
339
	$wgEnotifUseRealName = false;
340
	$wgEnotifUserTalk = false;
341
	$wgEnotifWatchlist = false;
342
	unset( $wgGroupPermissions['user']['sendemail'] );
343
	$wgUseEnotif = false;
344
	$wgUserEmailUseReplyTo = false;
345
	$wgUsersNotifiedOnAllChanges = [];
346
}
347
348
if ( $wgMetaNamespace === false ) {
349
	$wgMetaNamespace = str_replace( ' ', '_', $wgSitename );
350
}
351
352
// Default value is 2000 or the suhosin limit if it is between 1 and 2000
353
if ( $wgResourceLoaderMaxQueryLength === false ) {
354
	$suhosinMaxValueLength = (int)ini_get( 'suhosin.get.max_value_length' );
355
	if ( $suhosinMaxValueLength > 0 && $suhosinMaxValueLength < 2000 ) {
356
		$wgResourceLoaderMaxQueryLength = $suhosinMaxValueLength;
357
	} else {
358
		$wgResourceLoaderMaxQueryLength = 2000;
359
	}
360
	unset( $suhosinMaxValueLength );
361
}
362
363
// Ensure the minimum chunk size is less than PHP upload limits or the maximum
364
// upload size.
365
$wgMinUploadChunkSize = min(
366
	$wgMinUploadChunkSize,
367
	UploadBase::getMaxUploadSize( 'file' ),
368
	UploadBase::getMaxPhpUploadSize(),
369
	( wfShorthandToInteger(
370
		ini_get( 'post_max_size' ) ?: ini_get( 'hhvm.server.max_post_size' ),
371
		PHP_INT_MAX
372
	) ?: PHP_INT_MAX ) - 1024 // Leave some room for other POST parameters
373
);
374
375
/**
376
 * Definitions of the NS_ constants are in Defines.php
377
 * @private
378
 */
379
$wgCanonicalNamespaceNames = [
380
	NS_MEDIA            => 'Media',
381
	NS_SPECIAL          => 'Special',
382
	NS_TALK             => 'Talk',
383
	NS_USER             => 'User',
384
	NS_USER_TALK        => 'User_talk',
385
	NS_PROJECT          => 'Project',
386
	NS_PROJECT_TALK     => 'Project_talk',
387
	NS_FILE             => 'File',
388
	NS_FILE_TALK        => 'File_talk',
389
	NS_MEDIAWIKI        => 'MediaWiki',
390
	NS_MEDIAWIKI_TALK   => 'MediaWiki_talk',
391
	NS_TEMPLATE         => 'Template',
392
	NS_TEMPLATE_TALK    => 'Template_talk',
393
	NS_HELP             => 'Help',
394
	NS_HELP_TALK        => 'Help_talk',
395
	NS_CATEGORY         => 'Category',
396
	NS_CATEGORY_TALK    => 'Category_talk',
397
];
398
399
/// @todo UGLY UGLY
400
if ( is_array( $wgExtraNamespaces ) ) {
401
	$wgCanonicalNamespaceNames = $wgCanonicalNamespaceNames + $wgExtraNamespaces;
402
}
403
404
// These are now the same, always
405
// To determine the user language, use $wgLang->getCode()
406
$wgContLanguageCode = $wgLanguageCode;
407
408
// Easy to forget to falsify $wgDebugToolbar for static caches.
409
// If file cache or CDN cache is on, just disable this (DWIMD).
410
if ( $wgUseFileCache || $wgUseSquid ) {
411
	$wgDebugToolbar = false;
412
}
413
414
// We always output HTML5 since 1.22, overriding these is no longer supported
415
// we set them here for extensions that depend on its value.
416
$wgHtml5 = true;
417
$wgXhtmlDefaultNamespace = 'http://www.w3.org/1999/xhtml';
418
$wgJsMimeType = 'text/javascript';
419
420
// Blacklisted file extensions shouldn't appear on the "allowed" list
421
$wgFileExtensions = array_values( array_diff( $wgFileExtensions, $wgFileBlacklist ) );
422
423
if ( $wgInvalidateCacheOnLocalSettingsChange ) {
424
	MediaWiki\suppressWarnings();
425
	$wgCacheEpoch = max( $wgCacheEpoch, gmdate( 'YmdHis', filemtime( "$IP/LocalSettings.php" ) ) );
426
	MediaWiki\restoreWarnings();
427
}
428
429
if ( $wgNewUserLog ) {
430
	// Add a new log type
431
	$wgLogTypes[] = 'newusers';
432
	$wgLogNames['newusers'] = 'newuserlogpage';
433
	$wgLogHeaders['newusers'] = 'newuserlogpagetext';
434
	$wgLogActionsHandlers['newusers/newusers'] = 'NewUsersLogFormatter';
435
	$wgLogActionsHandlers['newusers/create'] = 'NewUsersLogFormatter';
436
	$wgLogActionsHandlers['newusers/create2'] = 'NewUsersLogFormatter';
437
	$wgLogActionsHandlers['newusers/byemail'] = 'NewUsersLogFormatter';
438
	$wgLogActionsHandlers['newusers/autocreate'] = 'NewUsersLogFormatter';
439
}
440
441
if ( $wgPageLanguageUseDB ) {
442
	$wgLogTypes[] = 'pagelang';
443
	$wgLogActionsHandlers['pagelang/pagelang'] = 'PageLangLogFormatter';
444
}
445
446
if ( $wgCookieSecure === 'detect' ) {
447
	$wgCookieSecure = ( WebRequest::detectProtocol() === 'https' );
448
}
449
450
if ( $wgProfileOnly ) {
451
	$wgDebugLogGroups['profileoutput'] = $wgDebugLogFile;
452
	$wgDebugLogFile = '';
453
}
454
455
// Backwards compatibility with old password limits
456
if ( $wgMinimalPasswordLength !== false ) {
457
	$wgPasswordPolicy['policies']['default']['MinimalPasswordLength'] = $wgMinimalPasswordLength;
458
}
459
460
if ( $wgMaximalPasswordLength !== false ) {
461
	$wgPasswordPolicy['policies']['default']['MaximalPasswordLength'] = $wgMaximalPasswordLength;
462
}
463
464
// Backwards compatibility warning
465
if ( !$wgSessionsInObjectCache && !$wgSessionsInMemcached ) {
466
	wfDeprecated( '$wgSessionsInObjectCache = false', '1.27' );
467
	if ( $wgSessionHandler ) {
468
		wfDeprecated( '$wgSessionsHandler', '1.27' );
469
	}
470
	$cacheType = get_class( ObjectCache::getInstance( $wgSessionCacheType ) );
471
	wfDebugLog(
472
		'caches',
473
		"Session data will be stored in \"$cacheType\" cache with " .
474
			"expiry $wgObjectCacheSessionExpiry seconds"
475
	);
476
}
477
$wgSessionsInObjectCache = true;
478
479
if ( $wgPHPSessionHandling !== 'enable' &&
480
	$wgPHPSessionHandling !== 'warn' &&
481
	$wgPHPSessionHandling !== 'disable'
482
) {
483
	$wgPHPSessionHandling = 'warn';
484
}
485
if ( defined( 'MW_NO_SESSION' ) ) {
486
	// If the entry point wants no session, force 'disable' here unless they
487
	// specifically set it to the (undocumented) 'warn'.
488
	$wgPHPSessionHandling = MW_NO_SESSION === 'warn' ? 'warn' : 'disable';
489
}
490
491
Profiler::instance()->scopedProfileOut( $ps_default );
492
493
// Disable MWDebug for command line mode, this prevents MWDebug from eating up
494
// all the memory from logging SQL queries on maintenance scripts
495
global $wgCommandLineMode;
496
if ( $wgDebugToolbar && !$wgCommandLineMode ) {
497
	MWDebug::init();
498
}
499
500
if ( !class_exists( 'AutoLoader' ) ) {
501
	require_once "$IP/includes/AutoLoader.php";
502
}
503
504
// Reset the global service locator, so any services that have already been created will be
505
// re-created while taking into account any custom settings and extensions.
506
MediaWikiServices::resetGlobalInstance( new GlobalVarConfig(), 'quick' );
507
508
if ( $wgSharedDB && $wgSharedTables ) {
509
	// Apply $wgSharedDB table aliases for the local LB (all non-foreign DB connections)
510
	MediaWikiServices::getInstance()->getDBLoadBalancer()->setTableAliases(
511
		array_fill_keys(
512
			$wgSharedTables,
513
			[
514
				'dbname' => $wgSharedDB,
515
				'schema' => $wgSharedSchema,
516
				'prefix' => $wgSharedPrefix
517
			]
518
		)
519
	);
520
}
521
522
// Define a constant that indicates that the bootstrapping of the service locator
523
// is complete.
524
define( 'MW_SERVICE_BOOTSTRAP_COMPLETE', 1 );
525
526
// Install a header callback to prevent caching of responses with cookies (T127993)
527
if ( !$wgCommandLineMode ) {
528
	header_register_callback( function () {
529
		$headers = [];
530
		foreach ( headers_list() as $header ) {
531
			list( $name, $value ) = explode( ':', $header, 2 );
532
			$headers[strtolower( trim( $name ) )][] = trim( $value );
533
		}
534
535
		if ( isset( $headers['set-cookie'] ) ) {
536
			$cacheControl = isset( $headers['cache-control'] )
537
				? implode( ', ', $headers['cache-control'] )
538
				: '';
539
540
			if ( !preg_match( '/(?:^|,)\s*(?:private|no-cache|no-store)\s*(?:$|,)/i', $cacheControl ) ) {
541
				header( 'Expires: Thu, 01 Jan 1970 00:00:00 GMT' );
542
				header( 'Cache-Control: private, max-age=0, s-maxage=0' );
543
				MediaWiki\Logger\LoggerFactory::getInstance( 'cache-cookies' )->warning(
544
					'Cookies set on {url} with Cache-Control "{cache-control}"', [
545
						'url' => WebRequest::getGlobalRequestURL(),
546
						'cookies' => $headers['set-cookie'],
547
						'cache-control' => $cacheControl ?: '<not set>',
548
					]
549
				);
550
			}
551
		}
552
	} );
553
}
554
555
MWExceptionHandler::installHandler();
556
557
require_once "$IP/includes/compat/normal/UtfNormalUtil.php";
558
559
$ps_validation = Profiler::instance()->scopedProfileIn( $fname . '-validation' );
560
561
// T48998: Bail out early if $wgArticlePath is non-absolute
562
foreach ( [ 'wgArticlePath', 'wgVariantArticlePath' ] as $varName ) {
563
	if ( $$varName && !preg_match( '/^(https?:\/\/|\/)/', $$varName ) ) {
564
		throw new FatalError(
565
			"If you use a relative URL for \$$varName, it must start " .
566
			'with a slash (<code>/</code>).<br><br>See ' .
567
			"<a href=\"https://www.mediawiki.org/wiki/Manual:\$$varName\">" .
568
			"https://www.mediawiki.org/wiki/Manual:\$$varName</a>."
569
		);
570
	}
571
}
572
573
Profiler::instance()->scopedProfileOut( $ps_validation );
574
575
$ps_default2 = Profiler::instance()->scopedProfileIn( $fname . '-defaults2' );
576
577
if ( $wgCanonicalServer === false ) {
578
	$wgCanonicalServer = wfExpandUrl( $wgServer, PROTO_HTTP );
579
}
580
581
// Set server name
582
$serverParts = wfParseUrl( $wgCanonicalServer );
583
if ( $wgServerName !== false ) {
584
	wfWarn( '$wgServerName should be derived from $wgCanonicalServer, '
585
		. 'not customized. Overwriting $wgServerName.' );
586
}
587
$wgServerName = $serverParts['host'];
588
unset( $serverParts );
589
590
// Set defaults for configuration variables
591
// that are derived from the server name by default
592
// Note: $wgEmergencyContact and $wgPasswordSender may be false or empty string (T104142)
593
if ( !$wgEmergencyContact ) {
594
	$wgEmergencyContact = 'wikiadmin@' . $wgServerName;
595
}
596
if ( !$wgPasswordSender ) {
597
	$wgPasswordSender = 'apache@' . $wgServerName;
598
}
599
if ( !$wgNoReplyAddress ) {
600
	$wgNoReplyAddress = $wgPasswordSender;
601
}
602
603
if ( $wgSecureLogin && substr( $wgServer, 0, 2 ) !== '//' ) {
604
	$wgSecureLogin = false;
605
	wfWarn( 'Secure login was enabled on a server that only supports '
606
		. 'HTTP or HTTPS. Disabling secure login.' );
607
}
608
609
$wgVirtualRestConfig['global']['domain'] = $wgCanonicalServer;
610
611
// Now that GlobalFunctions is loaded, set defaults that depend on it.
612
if ( $wgTmpDirectory === false ) {
613
	$wgTmpDirectory = wfTempDir();
614
}
615
616
// We don't use counters anymore. Left here for extensions still
617
// expecting this to exist. Should be removed sometime 1.26 or later.
618
if ( !isset( $wgDisableCounters ) ) {
619
	$wgDisableCounters = true;
620
}
621
622
if ( $wgMainWANCache === false ) {
623
	// Setup a WAN cache from $wgMainCacheType with no relayer.
624
	// Sites using multiple datacenters can configure a relayer.
625
	$wgMainWANCache = 'mediawiki-main-default';
626
	$wgWANObjectCaches[$wgMainWANCache] = [
627
		'class'    => 'WANObjectCache',
628
		'cacheId'  => $wgMainCacheType,
629
		'channels' => [ 'purge' => 'wancache-main-default-purge' ]
630
	];
631
}
632
633
Profiler::instance()->scopedProfileOut( $ps_default2 );
634
635
$ps_misc = Profiler::instance()->scopedProfileIn( $fname . '-misc1' );
636
637
// Raise the memory limit if it's too low
638
wfMemoryLimit();
639
640
/**
641
 * Set up the timezone, suppressing the pseudo-security warning in PHP 5.1+
642
 * that happens whenever you use a date function without the timezone being
643
 * explicitly set. Inspired by phpMyAdmin's treatment of the problem.
644
 */
645
if ( is_null( $wgLocaltimezone ) ) {
646
	MediaWiki\suppressWarnings();
647
	$wgLocaltimezone = date_default_timezone_get();
648
	MediaWiki\restoreWarnings();
649
}
650
651
date_default_timezone_set( $wgLocaltimezone );
652
if ( is_null( $wgLocalTZoffset ) ) {
653
	$wgLocalTZoffset = date( 'Z' ) / 60;
654
}
655
// The part after the System| is ignored, but rest of MW fills it
656
// out as the local offset.
657
$wgDefaultUserOptions['timecorrection'] = "System|$wgLocalTZoffset";
658
659
if ( !$wgDBerrorLogTZ ) {
660
	$wgDBerrorLogTZ = $wgLocaltimezone;
661
}
662
663
// initialize the request object in $wgRequest
664
$wgRequest = RequestContext::getMain()->getRequest(); // BackCompat
665
// Set user IP/agent information for causal consistency purposes
666
MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->setRequestInfo( [
667
	'IPAddress' => $wgRequest->getIP(),
668
	'UserAgent' => $wgRequest->getHeader( 'User-Agent' ),
669
	'ChronologyProtection' => $wgRequest->getHeader( 'ChronologyProtection' )
670
] );
671
672
// Useful debug output
673
if ( $wgCommandLineMode ) {
674
	wfDebug( "\n\nStart command line script $self\n" );
675
} else {
676
	$debug = "\n\nStart request {$wgRequest->getMethod()} {$wgRequest->getRequestURL()}\n";
677
678
	if ( $wgDebugPrintHttpHeaders ) {
679
		$debug .= "HTTP HEADERS:\n";
680
681
		foreach ( $wgRequest->getAllHeaders() as $name => $value ) {
682
			$debug .= "$name: $value\n";
683
		}
684
	}
685
	wfDebug( $debug );
686
}
687
688
Profiler::instance()->scopedProfileOut( $ps_misc );
689
$ps_memcached = Profiler::instance()->scopedProfileIn( $fname . '-memcached' );
690
691
$wgMemc = wfGetMainCache();
692
$messageMemc = wfGetMessageCacheStorage();
693
$parserMemc = wfGetParserCacheStorage();
694
695
wfDebugLog( 'caches',
696
	'cluster: ' . get_class( $wgMemc ) .
697
	', WAN: ' . ( $wgMainWANCache === CACHE_NONE ? 'CACHE_NONE' : $wgMainWANCache ) .
698
	', stash: ' . $wgMainStash .
699
	', message: ' . get_class( $messageMemc ) .
700
	', parser: ' . get_class( $parserMemc ) .
701
	', session: ' . get_class( ObjectCache::getInstance( $wgSessionCacheType ) )
702
);
703
704
Profiler::instance()->scopedProfileOut( $ps_memcached );
705
706
// Most of the config is out, some might want to run hooks here.
707
Hooks::run( 'SetupAfterCache' );
708
709
$ps_globals = Profiler::instance()->scopedProfileIn( $fname . '-globals' );
710
711
/**
712
 * @var Language $wgContLang
713
 */
714
$wgContLang = Language::factory( $wgLanguageCode );
715
$wgContLang->initContLang();
716
717
// Now that variant lists may be available...
718
$wgRequest->interpolateTitle();
719
720
if ( !is_object( $wgAuth ) ) {
721
	$wgAuth = new MediaWiki\Auth\AuthManagerAuthPlugin;
0 ignored issues
show
Deprecated Code introduced by
The class MediaWiki\Auth\AuthManagerAuthPlugin has been deprecated with message: since 1.27

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
722
	Hooks::run( 'AuthPluginSetup', [ &$wgAuth ] );
723
}
724
if ( $wgAuth && !$wgAuth instanceof MediaWiki\Auth\AuthManagerAuthPlugin ) {
725
	MediaWiki\Auth\AuthManager::singleton()->forcePrimaryAuthenticationProviders( [
726
		new MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider( [
727
			'authoritative' => false,
728
		] ),
729
		new MediaWiki\Auth\AuthPluginPrimaryAuthenticationProvider( $wgAuth ),
730
		new MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider( [
731
			'authoritative' => true,
732
		] ),
733
	], '$wgAuth is ' . get_class( $wgAuth ) );
734
}
735
736
// Set up the session
737
$ps_session = Profiler::instance()->scopedProfileIn( $fname . '-session' );
738
/**
739
 * @var MediaWiki\Session\SessionId|null $wgInitialSessionId The persistent
740
 * session ID (if any) loaded at startup
741
 */
742
$wgInitialSessionId = null;
743
if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) {
744
	// If session.auto_start is there, we can't touch session name
745
	if ( $wgPHPSessionHandling !== 'disable' && !wfIniGetBool( 'session.auto_start' ) ) {
746
		session_name( $wgSessionName ? $wgSessionName : $wgCookiePrefix . '_session' );
747
	}
748
749
	// Create the SessionManager singleton and set up our session handler,
750
	// unless we're specifically asked not to.
751
	if ( !defined( 'MW_NO_SESSION_HANDLER' ) ) {
752
		MediaWiki\Session\PHPSessionHandler::install(
753
			MediaWiki\Session\SessionManager::singleton()
754
		);
755
	}
756
757
	// Initialize the session
758
	try {
759
		$session = MediaWiki\Session\SessionManager::getGlobalSession();
760
	} catch ( OverflowException $ex ) {
761
		if ( isset( $ex->sessionInfos ) && count( $ex->sessionInfos ) >= 2 ) {
762
			// The exception is because the request had multiple possible
763
			// sessions tied for top priority. Report this to the user.
764
			$list = [];
765
			foreach ( $ex->sessionInfos as $info ) {
766
				$list[] = $info->getProvider()->describe( $wgContLang );
767
			}
768
			$list = $wgContLang->listToText( $list );
769
			throw new HttpError( 400,
770
				Message::newFromKey( 'sessionmanager-tie', $list )->inLanguage( $wgContLang )->plain()
771
			);
772
		}
773
774
		// Not the one we want, rethrow
775
		throw $ex;
776
	}
777
778
	if ( $session->isPersistent() ) {
779
		$wgInitialSessionId = $session->getSessionId();
780
	}
781
782
	$session->renew();
783
	if ( MediaWiki\Session\PHPSessionHandler::isEnabled() &&
784
		( $session->isPersistent() || $session->shouldRememberUser() )
785
	) {
786
		// Start the PHP-session for backwards compatibility
787
		session_id( $session->getId() );
788
		MediaWiki\quietCall( 'session_start' );
789
	}
790
791
	unset( $session );
792
} else {
793
	// Even if we didn't set up a global Session, still install our session
794
	// handler unless specifically requested not to.
795
	if ( !defined( 'MW_NO_SESSION_HANDLER' ) ) {
796
		MediaWiki\Session\PHPSessionHandler::install(
797
			MediaWiki\Session\SessionManager::singleton()
798
		);
799
	}
800
}
801
Profiler::instance()->scopedProfileOut( $ps_session );
802
803
/**
804
 * @var User $wgUser
805
 */
806
$wgUser = RequestContext::getMain()->getUser(); // BackCompat
807
808
/**
809
 * @var Language $wgLang
810
 */
811
$wgLang = new StubUserLang;
812
813
/**
814
 * @var OutputPage $wgOut
815
 */
816
$wgOut = RequestContext::getMain()->getOutput(); // BackCompat
817
818
/**
819
 * @var Parser $wgParser
820
 */
821
$wgParser = new StubObject( 'wgParser', function () {
822
	return MediaWikiServices::getInstance()->getParser();
823
} );
824
825
/**
826
 * @var Title $wgTitle
827
 */
828
$wgTitle = null;
829
830
Profiler::instance()->scopedProfileOut( $ps_globals );
831
$ps_extensions = Profiler::instance()->scopedProfileIn( $fname . '-extensions' );
832
833
// Extension setup functions
834
// Entries should be added to this variable during the inclusion
835
// of the extension file. This allows the extension to perform
836
// any necessary initialisation in the fully initialised environment
837
foreach ( $wgExtensionFunctions as $func ) {
838
	// Allow closures in PHP 5.3+
839
	if ( is_object( $func ) && $func instanceof Closure ) {
840
		$profName = $fname . '-extensions-closure';
841
	} elseif ( is_array( $func ) ) {
842
		if ( is_object( $func[0] ) ) {
843
			$profName = $fname . '-extensions-' . get_class( $func[0] ) . '::' . $func[1];
844
		} else {
845
			$profName = $fname . '-extensions-' . implode( '::', $func );
846
		}
847
	} else {
848
		$profName = $fname . '-extensions-' . strval( $func );
849
	}
850
851
	$ps_ext_func = Profiler::instance()->scopedProfileIn( $profName );
852
	call_user_func( $func );
853
	Profiler::instance()->scopedProfileOut( $ps_ext_func );
854
}
855
856
// If the session user has a 0 id but a valid name, that means we need to
857
// autocreate it.
858
if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) {
859
	$sessionUser = MediaWiki\Session\SessionManager::getGlobalSession()->getUser();
860
	if ( $sessionUser->getId() === 0 && User::isValidUserName( $sessionUser->getName() ) ) {
861
		$ps_autocreate = Profiler::instance()->scopedProfileIn( $fname . '-autocreate' );
862
		$res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser(
863
			$sessionUser,
864
			MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION,
865
			true
866
		);
867
		Profiler::instance()->scopedProfileOut( $ps_autocreate );
868
		\MediaWiki\Logger\LoggerFactory::getInstance( 'authevents' )->info( 'Autocreation attempt', [
869
			'event' => 'autocreate',
870
			'status' => $res,
871
		] );
872
		unset( $res );
873
	}
874
	unset( $sessionUser );
875
}
876
877
if ( !$wgCommandLineMode ) {
878
	Pingback::schedulePingback();
879
}
880
881
wfDebug( "Fully initialised\n" );
882
$wgFullyInitialised = true;
883
884
Profiler::instance()->scopedProfileOut( $ps_extensions );
885
Profiler::instance()->scopedProfileOut( $ps_setup );
886