Issues (4122)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/parser/ParserOptions.php (2 issues)

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
 * Options for the PHP parser
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @ingroup Parser
22
 */
23
use Wikimedia\ScopedCallback;
0 ignored issues
show
This use statement conflicts with another class in this namespace, ScopedCallback.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
24
25
/**
26
 * @brief Set options of the Parser
27
 *
28
 * All member variables are supposed to be private in theory, although in
29
 * practice this is not the case.
30
 *
31
 * @ingroup Parser
32
 */
33
class ParserOptions {
34
35
	/**
36
	 * Interlanguage links are removed and returned in an array
37
	 */
38
	private $mInterwikiMagic;
39
40
	/**
41
	 * Allow external images inline?
42
	 */
43
	private $mAllowExternalImages;
44
45
	/**
46
	 * If not, any exception?
47
	 */
48
	private $mAllowExternalImagesFrom;
49
50
	/**
51
	 * If not or it doesn't match, should we check an on-wiki whitelist?
52
	 */
53
	private $mEnableImageWhitelist;
54
55
	/**
56
	 * Date format index
57
	 */
58
	private $mDateFormat = null;
59
60
	/**
61
	 * Create "edit section" links?
62
	 */
63
	private $mEditSection = true;
64
65
	/**
66
	 * Allow inclusion of special pages?
67
	 */
68
	private $mAllowSpecialInclusion;
69
70
	/**
71
	 * Use tidy to cleanup output HTML?
72
	 */
73
	private $mTidy = false;
74
75
	/**
76
	 * Which lang to call for PLURAL and GRAMMAR
77
	 */
78
	private $mInterfaceMessage = false;
79
80
	/**
81
	 * Overrides $mInterfaceMessage with arbitrary language
82
	 */
83
	private $mTargetLanguage = null;
84
85
	/**
86
	 * Maximum size of template expansions, in bytes
87
	 */
88
	private $mMaxIncludeSize;
89
90
	/**
91
	 * Maximum number of nodes touched by PPFrame::expand()
92
	 */
93
	private $mMaxPPNodeCount;
94
95
	/**
96
	 * Maximum number of nodes generated by Preprocessor::preprocessToObj()
97
	 */
98
	private $mMaxGeneratedPPNodeCount;
99
100
	/**
101
	 * Maximum recursion depth in PPFrame::expand()
102
	 */
103
	private $mMaxPPExpandDepth;
104
105
	/**
106
	 * Maximum recursion depth for templates within templates
107
	 */
108
	private $mMaxTemplateDepth;
109
110
	/**
111
	 * Maximum number of calls per parse to expensive parser functions
112
	 */
113
	private $mExpensiveParserFunctionLimit;
114
115
	/**
116
	 * Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS
117
	 */
118
	private $mRemoveComments = true;
119
120
	/**
121
	 * @var callable Callback for current revision fetching; first argument to call_user_func().
122
	 */
123
	private $mCurrentRevisionCallback =
124
		[ 'Parser', 'statelessFetchRevision' ];
125
126
	/**
127
	 * @var callable Callback for template fetching; first argument to call_user_func().
128
	 */
129
	private $mTemplateCallback =
130
		[ 'Parser', 'statelessFetchTemplate' ];
131
132
	/**
133
	 * @var callable|null Callback to generate a guess for {{REVISIONID}}
134
	 */
135
	private $mSpeculativeRevIdCallback;
136
137
	/**
138
	 * Enable limit report in an HTML comment on output
139
	 */
140
	private $mEnableLimitReport = false;
141
142
	/**
143
	 * Timestamp used for {{CURRENTDAY}} etc.
144
	 */
145
	private $mTimestamp;
146
147
	/**
148
	 * Target attribute for external links
149
	 */
150
	private $mExternalLinkTarget;
151
152
	/**
153
	 * Clean up signature texts?
154
	 * @see Parser::cleanSig
155
	 */
156
	private $mCleanSignatures;
157
158
	/**
159
	 * Transform wiki markup when saving the page?
160
	 */
161
	private $mPreSaveTransform = true;
162
163
	/**
164
	 * Whether content conversion should be disabled
165
	 */
166
	private $mDisableContentConversion;
167
168
	/**
169
	 * Whether title conversion should be disabled
170
	 */
171
	private $mDisableTitleConversion;
172
173
	/**
174
	 * Automatically number headings?
175
	 */
176
	private $mNumberHeadings;
177
178
	/**
179
	 * Thumb size preferred by the user.
180
	 */
181
	private $mThumbSize;
182
183
	/**
184
	 * Maximum article size of an article to be marked as "stub"
185
	 */
186
	private $mStubThreshold;
187
188
	/**
189
	 * Language object of the User language.
190
	 */
191
	private $mUserLang;
192
193
	/**
194
	 * @var User
195
	 * Stored user object
196
	 */
197
	private $mUser;
198
199
	/**
200
	 * Parsing the page for a "preview" operation?
201
	 */
202
	private $mIsPreview = false;
203
204
	/**
205
	 * Parsing the page for a "preview" operation on a single section?
206
	 */
207
	private $mIsSectionPreview = false;
208
209
	/**
210
	 * Parsing the printable version of the page?
211
	 */
212
	private $mIsPrintable = false;
213
214
	/**
215
	 * Extra key that should be present in the caching key.
216
	 */
217
	private $mExtraKey = '';
218
219
	/**
220
	 * Are magic ISBN links enabled?
221
	 */
222
	private $mMagicISBNLinks = true;
223
224
	/**
225
	 * Are magic PMID links enabled?
226
	 */
227
	private $mMagicPMIDLinks = true;
228
229
	/**
230
	 * Are magic RFC links enabled?
231
	 */
232
	private $mMagicRFCLinks = true;
233
234
	/**
235
	 * Function to be called when an option is accessed.
236
	 */
237
	private $onAccessCallback = null;
238
239
	/**
240
	 * If the page being parsed is a redirect, this should hold the redirect
241
	 * target.
242
	 * @var Title|null
243
	 */
244
	private $redirectTarget = null;
245
246
	public function getInterwikiMagic() {
247
		return $this->mInterwikiMagic;
248
	}
249
250
	public function getAllowExternalImages() {
251
		return $this->mAllowExternalImages;
252
	}
253
254
	public function getAllowExternalImagesFrom() {
255
		return $this->mAllowExternalImagesFrom;
256
	}
257
258
	public function getEnableImageWhitelist() {
259
		return $this->mEnableImageWhitelist;
260
	}
261
262
	public function getEditSection() {
263
		return $this->mEditSection;
264
	}
265
266
	public function getNumberHeadings() {
267
		$this->optionUsed( 'numberheadings' );
268
269
		return $this->mNumberHeadings;
270
	}
271
272
	public function getAllowSpecialInclusion() {
273
		return $this->mAllowSpecialInclusion;
274
	}
275
276
	public function getTidy() {
277
		return $this->mTidy;
278
	}
279
280
	public function getInterfaceMessage() {
281
		return $this->mInterfaceMessage;
282
	}
283
284
	public function getTargetLanguage() {
285
		return $this->mTargetLanguage;
286
	}
287
288
	public function getMaxIncludeSize() {
289
		return $this->mMaxIncludeSize;
290
	}
291
292
	public function getMaxPPNodeCount() {
293
		return $this->mMaxPPNodeCount;
294
	}
295
296
	public function getMaxGeneratedPPNodeCount() {
297
		return $this->mMaxGeneratedPPNodeCount;
298
	}
299
300
	public function getMaxPPExpandDepth() {
301
		return $this->mMaxPPExpandDepth;
302
	}
303
304
	public function getMaxTemplateDepth() {
305
		return $this->mMaxTemplateDepth;
306
	}
307
308
	/* @since 1.20 */
309
	public function getExpensiveParserFunctionLimit() {
310
		return $this->mExpensiveParserFunctionLimit;
311
	}
312
313
	public function getRemoveComments() {
314
		return $this->mRemoveComments;
315
	}
316
317
	/* @since 1.24 */
318
	public function getCurrentRevisionCallback() {
319
		return $this->mCurrentRevisionCallback;
320
	}
321
322
	public function getTemplateCallback() {
323
		return $this->mTemplateCallback;
324
	}
325
326
	/** @since 1.28 */
327
	public function getSpeculativeRevIdCallback() {
328
		return $this->mSpeculativeRevIdCallback;
329
	}
330
331
	public function getEnableLimitReport() {
332
		return $this->mEnableLimitReport;
333
	}
334
335
	public function getCleanSignatures() {
336
		return $this->mCleanSignatures;
337
	}
338
339
	public function getExternalLinkTarget() {
340
		return $this->mExternalLinkTarget;
341
	}
342
343
	public function getDisableContentConversion() {
344
		return $this->mDisableContentConversion;
345
	}
346
347
	public function getDisableTitleConversion() {
348
		return $this->mDisableTitleConversion;
349
	}
350
351
	public function getThumbSize() {
352
		$this->optionUsed( 'thumbsize' );
353
354
		return $this->mThumbSize;
355
	}
356
357
	public function getStubThreshold() {
358
		$this->optionUsed( 'stubthreshold' );
359
360
		return $this->mStubThreshold;
361
	}
362
363
	public function getIsPreview() {
364
		return $this->mIsPreview;
365
	}
366
367
	public function getIsSectionPreview() {
368
		return $this->mIsSectionPreview;
369
	}
370
371
	public function getIsPrintable() {
372
		$this->optionUsed( 'printable' );
373
374
		return $this->mIsPrintable;
375
	}
376
377
	public function getUser() {
378
		return $this->mUser;
379
	}
380
381
	public function getPreSaveTransform() {
382
		return $this->mPreSaveTransform;
383
	}
384
385
	public function getDateFormat() {
386
		$this->optionUsed( 'dateformat' );
387
		if ( !isset( $this->mDateFormat ) ) {
388
			$this->mDateFormat = $this->mUser->getDatePreference();
389
		}
390
		return $this->mDateFormat;
391
	}
392
393
	public function getTimestamp() {
394
		if ( !isset( $this->mTimestamp ) ) {
395
			$this->mTimestamp = wfTimestampNow();
396
		}
397
		return $this->mTimestamp;
398
	}
399
400
	/**
401
	 * Get the user language used by the parser for this page and split the parser cache.
402
	 *
403
	 * @warning: Calling this causes the parser cache to be fragmented by user language!
404
	 * To avoid cache fragmentation, output should not depend on the user language.
405
	 * Use Parser::getFunctionLang() or Parser::getTargetLanguage() instead!
406
	 *
407
	 * @note This function will trigger a cache fragmentation by recording the
408
	 * 'userlang' option, see optionUsed(). This is done to avoid cache pollution
409
	 * when the page is rendered based on the language of the user.
410
	 *
411
	 * @note When saving, this will return the default language instead of the user's.
412
	 * {{int: }} uses this which used to produce inconsistent link tables (bug 14404).
413
	 *
414
	 * @return Language
415
	 * @since 1.19
416
	 */
417
	public function getUserLangObj() {
418
		$this->optionUsed( 'userlang' );
419
		return $this->mUserLang;
420
	}
421
422
	/**
423
	 * Same as getUserLangObj() but returns a string instead.
424
	 *
425
	 * @warning: Calling this causes the parser cache to be fragmented by user language!
426
	 * To avoid cache fragmentation, output should not depend on the user language.
427
	 * Use Parser::getFunctionLang() or Parser::getTargetLanguage() instead!
428
	 *
429
	 * @see getUserLangObj()
430
	 *
431
	 * @return string Language code
432
	 * @since 1.17
433
	 */
434
	public function getUserLang() {
435
		return $this->getUserLangObj()->getCode();
436
	}
437
438
	/**
439
	 * @since 1.28
440
	 * @return bool
441
	 */
442
	public function getMagicISBNLinks() {
443
		return $this->mMagicISBNLinks;
444
	}
445
446
	/**
447
	 * @since 1.28
448
	 * @return bool
449
	 */
450
	public function getMagicPMIDLinks() {
451
		return $this->mMagicPMIDLinks;
452
	}
453
	/**
454
	 * @since 1.28
455
	 * @return bool
456
	 */
457
	public function getMagicRFCLinks() {
458
		return $this->mMagicRFCLinks;
459
	}
460
	public function setInterwikiMagic( $x ) {
461
		return wfSetVar( $this->mInterwikiMagic, $x );
462
	}
463
464
	public function setAllowExternalImages( $x ) {
465
		return wfSetVar( $this->mAllowExternalImages, $x );
466
	}
467
468
	public function setAllowExternalImagesFrom( $x ) {
469
		return wfSetVar( $this->mAllowExternalImagesFrom, $x );
470
	}
471
472
	public function setEnableImageWhitelist( $x ) {
473
		return wfSetVar( $this->mEnableImageWhitelist, $x );
474
	}
475
476
	public function setDateFormat( $x ) {
477
		return wfSetVar( $this->mDateFormat, $x );
478
	}
479
480
	public function setEditSection( $x ) {
481
		return wfSetVar( $this->mEditSection, $x );
482
	}
483
484
	public function setNumberHeadings( $x ) {
485
		return wfSetVar( $this->mNumberHeadings, $x );
486
	}
487
488
	public function setAllowSpecialInclusion( $x ) {
489
		return wfSetVar( $this->mAllowSpecialInclusion, $x );
490
	}
491
492
	public function setTidy( $x ) {
493
		return wfSetVar( $this->mTidy, $x );
494
	}
495
496
	public function setInterfaceMessage( $x ) {
497
		return wfSetVar( $this->mInterfaceMessage, $x );
498
	}
499
500
	public function setTargetLanguage( $x ) {
501
		return wfSetVar( $this->mTargetLanguage, $x, true );
502
	}
503
504
	public function setMaxIncludeSize( $x ) {
505
		return wfSetVar( $this->mMaxIncludeSize, $x );
506
	}
507
508
	public function setMaxPPNodeCount( $x ) {
509
		return wfSetVar( $this->mMaxPPNodeCount, $x );
510
	}
511
512
	public function setMaxGeneratedPPNodeCount( $x ) {
513
		return wfSetVar( $this->mMaxGeneratedPPNodeCount, $x );
514
	}
515
516
	public function setMaxTemplateDepth( $x ) {
517
		return wfSetVar( $this->mMaxTemplateDepth, $x );
518
	}
519
520
	/* @since 1.20 */
521
	public function setExpensiveParserFunctionLimit( $x ) {
522
		return wfSetVar( $this->mExpensiveParserFunctionLimit, $x );
523
	}
524
525
	public function setRemoveComments( $x ) {
526
		return wfSetVar( $this->mRemoveComments, $x );
527
	}
528
529
	/* @since 1.24 */
530
	public function setCurrentRevisionCallback( $x ) {
531
		return wfSetVar( $this->mCurrentRevisionCallback, $x );
532
	}
533
534
	/** @since 1.28 */
535
	public function setSpeculativeRevIdCallback( $x ) {
536
		return wfSetVar( $this->mSpeculativeRevIdCallback, $x );
537
	}
538
539
	public function setTemplateCallback( $x ) {
540
		return wfSetVar( $this->mTemplateCallback, $x );
541
	}
542
543
	public function enableLimitReport( $x = true ) {
544
		return wfSetVar( $this->mEnableLimitReport, $x );
545
	}
546
547
	public function setTimestamp( $x ) {
548
		return wfSetVar( $this->mTimestamp, $x );
549
	}
550
551
	public function setCleanSignatures( $x ) {
552
		return wfSetVar( $this->mCleanSignatures, $x );
553
	}
554
555
	public function setExternalLinkTarget( $x ) {
556
		return wfSetVar( $this->mExternalLinkTarget, $x );
557
	}
558
559
	public function disableContentConversion( $x = true ) {
560
		return wfSetVar( $this->mDisableContentConversion, $x );
561
	}
562
563
	public function disableTitleConversion( $x = true ) {
564
		return wfSetVar( $this->mDisableTitleConversion, $x );
565
	}
566
567
	public function setUserLang( $x ) {
568
		if ( is_string( $x ) ) {
569
			$x = Language::factory( $x );
570
		}
571
572
		return wfSetVar( $this->mUserLang, $x );
573
	}
574
575
	public function setThumbSize( $x ) {
576
		return wfSetVar( $this->mThumbSize, $x );
577
	}
578
579
	public function setStubThreshold( $x ) {
580
		return wfSetVar( $this->mStubThreshold, $x );
581
	}
582
583
	public function setPreSaveTransform( $x ) {
584
		return wfSetVar( $this->mPreSaveTransform, $x );
585
	}
586
587
	public function setIsPreview( $x ) {
588
		return wfSetVar( $this->mIsPreview, $x );
589
	}
590
591
	public function setIsSectionPreview( $x ) {
592
		return wfSetVar( $this->mIsSectionPreview, $x );
593
	}
594
595
	public function setIsPrintable( $x ) {
596
		return wfSetVar( $this->mIsPrintable, $x );
597
	}
598
599
	/**
600
	 * Set the redirect target.
601
	 *
602
	 * Note that setting or changing this does not *make* the page a redirect
603
	 * or change its target, it merely records the information for reference
604
	 * during the parse.
605
	 *
606
	 * @since 1.24
607
	 * @param Title|null $title
608
	 */
609
	function setRedirectTarget( $title ) {
610
		$this->redirectTarget = $title;
611
	}
612
613
	/**
614
	 * Get the previously-set redirect target.
615
	 *
616
	 * @since 1.24
617
	 * @return Title|null
618
	 */
619
	function getRedirectTarget() {
620
		return $this->redirectTarget;
621
	}
622
623
	/**
624
	 * Extra key that should be present in the parser cache key.
625
	 * @param string $key
626
	 */
627
	public function addExtraKey( $key ) {
628
		$this->mExtraKey .= '!' . $key;
629
	}
630
631
	/**
632
	 * Constructor
633
	 * @param User $user
634
	 * @param Language $lang
635
	 */
636
	public function __construct( $user = null, $lang = null ) {
637
		if ( $user === null ) {
638
			global $wgUser;
639
			if ( $wgUser === null ) {
640
				$user = new User;
641
			} else {
642
				$user = $wgUser;
643
			}
644
		}
645
		if ( $lang === null ) {
646
			global $wgLang;
647
			if ( !StubObject::isRealObject( $wgLang ) ) {
648
				$wgLang->_unstub();
649
			}
650
			$lang = $wgLang;
651
		}
652
		$this->initialiseFromUser( $user, $lang );
653
	}
654
655
	/**
656
	 * Get a ParserOptions object for an anonymous user
657
	 * @since 1.27
658
	 * @return ParserOptions
659
	 */
660
	public static function newFromAnon() {
661
		global $wgContLang;
662
		return new ParserOptions( new User, $wgContLang );
663
	}
664
665
	/**
666
	 * Get a ParserOptions object from a given user.
667
	 * Language will be taken from $wgLang.
668
	 *
669
	 * @param User $user
670
	 * @return ParserOptions
671
	 */
672
	public static function newFromUser( $user ) {
673
		return new ParserOptions( $user );
674
	}
675
676
	/**
677
	 * Get a ParserOptions object from a given user and language
678
	 *
679
	 * @param User $user
680
	 * @param Language $lang
681
	 * @return ParserOptions
682
	 */
683
	public static function newFromUserAndLang( User $user, Language $lang ) {
684
		return new ParserOptions( $user, $lang );
685
	}
686
687
	/**
688
	 * Get a ParserOptions object from a IContextSource object
689
	 *
690
	 * @param IContextSource $context
691
	 * @return ParserOptions
692
	 */
693
	public static function newFromContext( IContextSource $context ) {
694
		return new ParserOptions( $context->getUser(), $context->getLanguage() );
695
	}
696
697
	/**
698
	 * Get user options
699
	 *
700
	 * @param User $user
701
	 * @param Language $lang
702
	 */
703
	private function initialiseFromUser( $user, $lang ) {
704
		global $wgInterwikiMagic, $wgAllowExternalImages,
705
			$wgAllowExternalImagesFrom, $wgEnableImageWhitelist, $wgAllowSpecialInclusion,
706
			$wgMaxArticleSize, $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth,
707
			$wgCleanSignatures, $wgExternalLinkTarget, $wgExpensiveParserFunctionLimit,
708
			$wgMaxGeneratedPPNodeCount, $wgDisableLangConversion, $wgDisableTitleConversion,
709
			$wgEnableMagicLinks;
710
711
		// *UPDATE* ParserOptions::matches() if any of this changes as needed
712
		$this->mInterwikiMagic = $wgInterwikiMagic;
713
		$this->mAllowExternalImages = $wgAllowExternalImages;
714
		$this->mAllowExternalImagesFrom = $wgAllowExternalImagesFrom;
715
		$this->mEnableImageWhitelist = $wgEnableImageWhitelist;
716
		$this->mAllowSpecialInclusion = $wgAllowSpecialInclusion;
717
		$this->mMaxIncludeSize = $wgMaxArticleSize * 1024;
718
		$this->mMaxPPNodeCount = $wgMaxPPNodeCount;
719
		$this->mMaxGeneratedPPNodeCount = $wgMaxGeneratedPPNodeCount;
720
		$this->mMaxPPExpandDepth = $wgMaxPPExpandDepth;
721
		$this->mMaxTemplateDepth = $wgMaxTemplateDepth;
722
		$this->mExpensiveParserFunctionLimit = $wgExpensiveParserFunctionLimit;
723
		$this->mCleanSignatures = $wgCleanSignatures;
724
		$this->mExternalLinkTarget = $wgExternalLinkTarget;
725
		$this->mDisableContentConversion = $wgDisableLangConversion;
726
		$this->mDisableTitleConversion = $wgDisableLangConversion || $wgDisableTitleConversion;
727
		$this->mMagicISBNLinks = $wgEnableMagicLinks['ISBN'];
728
		$this->mMagicPMIDLinks = $wgEnableMagicLinks['PMID'];
729
		$this->mMagicRFCLinks = $wgEnableMagicLinks['RFC'];
730
731
		$this->mUser = $user;
732
		$this->mNumberHeadings = $user->getOption( 'numberheadings' );
733
		$this->mThumbSize = $user->getOption( 'thumbsize' );
734
		$this->mStubThreshold = $user->getStubThreshold();
735
		$this->mUserLang = $lang;
736
	}
737
738
	/**
739
	 * Check if these options match that of another options set
740
	 *
741
	 * This ignores report limit settings that only affect HTML comments
742
	 *
743
	 * @param ParserOptions $other
744
	 * @return bool
745
	 * @since 1.25
746
	 */
747
	public function matches( ParserOptions $other ) {
748
		$fields = array_keys( get_class_vars( __CLASS__ ) );
749
		$fields = array_diff( $fields, [
750
			'mEnableLimitReport', // only effects HTML comments
751
			'onAccessCallback', // only used for ParserOutput option tracking
752
		] );
753
		foreach ( $fields as $field ) {
754
			if ( !is_object( $this->$field ) && $this->$field !== $other->$field ) {
755
				return false;
756
			}
757
		}
758
		// Check the object and lazy-loaded options
759
		return (
760
			$this->mUserLang->equals( $other->mUserLang ) &&
761
			$this->getDateFormat() === $other->getDateFormat()
762
		);
763
	}
764
765
	/**
766
	 * Registers a callback for tracking which ParserOptions which are used.
767
	 * This is a private API with the parser.
768
	 * @param callable $callback
769
	 */
770
	public function registerWatcher( $callback ) {
771
		$this->onAccessCallback = $callback;
772
	}
773
774
	/**
775
	 * Called when an option is accessed.
776
	 * Calls the watcher that was set using registerWatcher().
777
	 * Typically, the watcher callback is ParserOutput::registerOption().
778
	 * The information registered that way will be used by ParserCache::save().
779
	 *
780
	 * @param string $optionName Name of the option
781
	 */
782
	public function optionUsed( $optionName ) {
783
		if ( $this->onAccessCallback ) {
784
			call_user_func( $this->onAccessCallback, $optionName );
785
		}
786
	}
787
788
	/**
789
	 * Returns the full array of options that would have been used by
790
	 * in 1.16.
791
	 * Used to get the old parser cache entries when available.
792
	 * @return array
793
	 */
794
	public static function legacyOptions() {
795
		return [
796
			'stubthreshold',
797
			'numberheadings',
798
			'userlang',
799
			'thumbsize',
800
			'editsection',
801
			'printable'
802
		];
803
	}
804
805
	/**
806
	 * Generate a hash string with the values set on these ParserOptions
807
	 * for the keys given in the array.
808
	 * This will be used as part of the hash key for the parser cache,
809
	 * so users sharing the options with vary for the same page share
810
	 * the same cached data safely.
811
	 *
812
	 * Extensions which require it should install 'PageRenderingHash' hook,
813
	 * which will give them a chance to modify this key based on their own
814
	 * settings.
815
	 *
816
	 * @since 1.17
817
	 * @param array $forOptions
818
	 * @param Title $title Used to get the content language of the page (since r97636)
819
	 * @return string Page rendering hash
820
	 */
821
	public function optionsHash( $forOptions, $title = null ) {
822
		global $wgRenderHashAppend;
823
824
		// FIXME: Once the cache key is reorganized this argument
825
		// can be dropped. It was used when the math extension was
826
		// part of core.
827
		$confstr = '*';
828
829
		// Space assigned for the stubthreshold but unused
830
		// since it disables the parser cache, its value will always
831
		// be 0 when this function is called by parsercache.
832
		if ( in_array( 'stubthreshold', $forOptions ) ) {
833
			$confstr .= '!' . $this->mStubThreshold;
834
		} else {
835
			$confstr .= '!*';
836
		}
837
838
		if ( in_array( 'dateformat', $forOptions ) ) {
839
			$confstr .= '!' . $this->getDateFormat();
840
		}
841
842
		if ( in_array( 'numberheadings', $forOptions ) ) {
843
			$confstr .= '!' . ( $this->mNumberHeadings ? '1' : '' );
844
		} else {
845
			$confstr .= '!*';
846
		}
847
848
		if ( in_array( 'userlang', $forOptions ) ) {
849
			$confstr .= '!' . $this->mUserLang->getCode();
850
		} else {
851
			$confstr .= '!*';
852
		}
853
854
		if ( in_array( 'thumbsize', $forOptions ) ) {
855
			$confstr .= '!' . $this->mThumbSize;
856
		} else {
857
			$confstr .= '!*';
858
		}
859
860
		// add in language specific options, if any
861
		// @todo FIXME: This is just a way of retrieving the url/user preferred variant
862
		if ( !is_null( $title ) ) {
863
			$confstr .= $title->getPageLanguage()->getExtraHashOptions();
864
		} else {
865
			global $wgContLang;
866
			$confstr .= $wgContLang->getExtraHashOptions();
867
		}
868
869
		$confstr .= $wgRenderHashAppend;
870
871
		// @note: as of Feb 2015, core never sets the editsection flag, since it uses
872
		// <mw:editsection> tags to inject editsections on the fly. However, extensions
873
		// may be using it by calling ParserOption::optionUsed resp. ParserOutput::registerOption
874
		// directly. At least Wikibase does at this point in time.
875
		if ( !in_array( 'editsection', $forOptions ) ) {
876
			$confstr .= '!*';
877
		} elseif ( !$this->mEditSection ) {
878
			$confstr .= '!edit=0';
879
		}
880
881
		if ( $this->mIsPrintable && in_array( 'printable', $forOptions ) ) {
882
			$confstr .= '!printable=1';
883
		}
884
885
		if ( $this->mExtraKey != '' ) {
886
			$confstr .= $this->mExtraKey;
887
		}
888
889
		// Give a chance for extensions to modify the hash, if they have
890
		// extra options or other effects on the parser cache.
891
		Hooks::run( 'PageRenderingHash', [ &$confstr, $this->getUser(), &$forOptions ] );
892
893
		// Make it a valid memcached key fragment
894
		$confstr = str_replace( ' ', '_', $confstr );
895
896
		return $confstr;
897
	}
898
899
	/**
900
	 * Sets a hook to force that a page exists, and sets a current revision callback to return
901
	 * a revision with custom content when the current revision of the page is requested.
902
	 *
903
	 * @since 1.25
904
	 * @param Title $title
905
	 * @param Content $content
906
	 * @param User $user The user that the fake revision is attributed to
907
	 * @return ScopedCallback to unset the hook
908
	 */
909
	public function setupFakeRevision( $title, $content, $user ) {
910
		$oldCallback = $this->setCurrentRevisionCallback(
0 ignored issues
show
$oldCallback is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
911
			function (
912
				$titleToCheck, $parser = false ) use ( $title, $content, $user, &$oldCallback
913
			) {
914
				if ( $titleToCheck->equals( $title ) ) {
915
					return new Revision( [
916
						'page' => $title->getArticleID(),
917
						'user_text' => $user->getName(),
918
						'user' => $user->getId(),
919
						'parent_id' => $title->getLatestRevID(),
920
						'title' => $title,
921
						'content' => $content
922
					] );
923
				} else {
924
					return call_user_func( $oldCallback, $titleToCheck, $parser );
925
				}
926
			}
927
		);
928
929
		global $wgHooks;
930
		$wgHooks['TitleExists'][] =
931
			function ( $titleToCheck, &$exists ) use ( $title ) {
932
				if ( $titleToCheck->equals( $title ) ) {
933
					$exists = true;
934
				}
935
			};
936
		end( $wgHooks['TitleExists'] );
937
		$key = key( $wgHooks['TitleExists'] );
938
		LinkCache::singleton()->clearBadLink( $title->getPrefixedDBkey() );
939
		return new ScopedCallback( function () use ( $title, $key ) {
940
			global $wgHooks;
941
			unset( $wgHooks['TitleExists'][$key] );
942
			LinkCache::singleton()->clearLink( $title );
943
		} );
944
	}
945
}
946