MediaWiki  master
CoreMagicWords.php
Go to the documentation of this file.
1 <?php
24 use Psr\Log\LoggerInterface;
25 
33  private const MAX_TTS = 900;
34 
47  public static function expand(
48  // Fundamental options
49  Parser $parser,
50  string $index,
51  // Context passed over from the parser
52  int $ts,
53  NamespaceInfo $nsInfo,
54  ServiceOptions $svcOptions,
55  LoggerInterface $logger
56  ): ?string {
57  $pageLang = $parser->getFunctionLang();
58  $title = $parser->getTitle();
59 
60  switch ( $index ) {
61  case '!':
62  return '|';
63  case 'currentmonth':
64  return $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'm' ), true );
65  case 'currentmonth1':
66  return $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'n' ), true );
67  case 'currentmonthname':
68  return $pageLang->getMonthName( MWTimestamp::getInstance( $ts )->format( 'n' ) );
69  case 'currentmonthnamegen':
70  return $pageLang->getMonthNameGen( MWTimestamp::getInstance( $ts )->format( 'n' ) );
71  case 'currentmonthabbrev':
72  return $pageLang->getMonthAbbreviation( MWTimestamp::getInstance( $ts )->format( 'n' ) );
73  case 'currentday':
74  return $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'j' ), true );
75  case 'currentday2':
76  return $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'd' ), true );
77  case 'localmonth':
78  return $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'm' ), true );
79  case 'localmonth1':
80  return $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'n' ), true );
81  case 'localmonthname':
82  return $pageLang->getMonthName( MWTimestamp::getLocalInstance( $ts )->format( 'n' ) );
83  case 'localmonthnamegen':
84  return $pageLang->getMonthNameGen( MWTimestamp::getLocalInstance( $ts )->format( 'n' ) );
85  case 'localmonthabbrev':
86  return $pageLang->getMonthAbbreviation( MWTimestamp::getLocalInstance( $ts )->format( 'n' ) );
87  case 'localday':
88  return $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'j' ), true );
89  case 'localday2':
90  return $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'd' ), true );
91  case 'pagename':
92  return wfEscapeWikiText( $title->getText() );
93  case 'pagenamee':
94  return wfEscapeWikiText( $title->getPartialURL() );
95  case 'fullpagename':
96  return wfEscapeWikiText( $title->getPrefixedText() );
97  case 'fullpagenamee':
98  return wfEscapeWikiText( $title->getPrefixedURL() );
99  case 'subpagename':
100  return wfEscapeWikiText( $title->getSubpageText() );
101  case 'subpagenamee':
102  return wfEscapeWikiText( $title->getSubpageUrlForm() );
103  case 'rootpagename':
104  return wfEscapeWikiText( $title->getRootText() );
105  case 'rootpagenamee':
106  return wfEscapeWikiText( wfUrlencode( str_replace(
107  ' ',
108  '_',
109  $title->getRootText()
110  ) ) );
111  case 'basepagename':
112  return wfEscapeWikiText( $title->getBaseText() );
113  case 'basepagenamee':
114  return wfEscapeWikiText( wfUrlencode( str_replace(
115  ' ',
116  '_',
117  $title->getBaseText()
118  ) ) );
119  case 'talkpagename':
120  if ( $title->canHaveTalkPage() ) {
121  $talkPage = $title->getTalkPage();
122  return wfEscapeWikiText( $talkPage->getPrefixedText() );
123  }
124  return '';
125  case 'talkpagenamee':
126  if ( $title->canHaveTalkPage() ) {
127  $talkPage = $title->getTalkPage();
128  return wfEscapeWikiText( $talkPage->getPrefixedURL() );
129  }
130  return '';
131  case 'subjectpagename':
132  $subjPage = $title->getSubjectPage();
133  return wfEscapeWikiText( $subjPage->getPrefixedText() );
134  case 'subjectpagenamee':
135  $subjPage = $title->getSubjectPage();
136  return wfEscapeWikiText( $subjPage->getPrefixedURL() );
137  case 'pageid': // requested in T25427
138  // Inform the edit saving system that getting the canonical output
139  // after page insertion requires a parse that used that exact page ID
140  self::setOutputFlag( $parser, $logger, 'vary-page-id', '{{PAGEID}} used' );
141  $value = $title->getArticleID();
142  if ( !$value ) {
143  $value = $parser->getOptions()->getSpeculativePageId();
144  if ( $value ) {
145  $parser->getOutput()->setSpeculativePageIdUsed( $value );
146  }
147  }
148  return (string)$value;
149  case 'revisionid':
150  $namespace = $title->getNamespace();
151  if (
152  $svcOptions->get( 'MiserMode' ) &&
153  !$parser->getOptions()->getInterfaceMessage() &&
154  // @TODO: disallow this word on all namespaces
155  $nsInfo->isSubject( $namespace )
156  ) {
157  // Use a stub result instead of the actual revision ID in order to avoid
158  // double parses on page save but still allow preview detection (T137900)
159  if ( $parser->getRevisionId() || $parser->getOptions()->getSpeculativeRevId() ) {
160  return '-';
161  } else {
162  self::setOutputFlag( $parser, $logger, 'vary-revision-exists', '{{REVISIONID}} used' );
163  return '';
164  }
165  } else {
166  // Inform the edit saving system that getting the canonical output after
167  // revision insertion requires a parse that used that exact revision ID
168  self::setOutputFlag( $parser, $logger, 'vary-revision-id', '{{REVISIONID}} used' );
169  $value = $parser->getRevisionId();
170  if ( $value === 0 ) {
171  $rev = $parser->getRevisionRecordObject();
172  $value = $rev ? $rev->getId() : $value;
173  }
174  if ( !$value ) {
175  $value = $parser->getOptions()->getSpeculativeRevId();
176  if ( $value ) {
177  $parser->getOutput()->setSpeculativeRevIdUsed( $value );
178  }
179  }
180  return (string)$value;
181  }
182  case 'revisionday':
183  return strval( (int)self::getRevisionTimestampSubstring(
184  $parser, $logger, 6, 2, self::MAX_TTS, $index
185  ) );
186  case 'revisionday2':
188  $parser, $logger, 6, 2, self::MAX_TTS, $index
189  );
190  case 'revisionmonth':
192  $parser, $logger, 4, 2, self::MAX_TTS, $index
193  );
194  case 'revisionmonth1':
195  return strval( (int)self::getRevisionTimestampSubstring(
196  $parser, $logger, 4, 2, self::MAX_TTS, $index
197  ) );
198  case 'revisionyear':
200  $parser, $logger, 0, 4, self::MAX_TTS, $index
201  );
202  case 'revisiontimestamp':
204  $parser, $logger, 0, 14, self::MAX_TTS, $index
205  );
206  case 'revisionuser':
207  // Inform the edit saving system that getting the canonical output after
208  // revision insertion requires a parse that used the actual user ID
209  self::setOutputFlag( $parser, $logger, 'vary-user', '{{REVISIONUSER}} used' );
210  // Note that getRevisionUser() can return null; we need to
211  // be sure to cast this to (an empty) string, since 'null'
212  // means "magic word not handled here".
213  return (string)$parser->getRevisionUser();
214  case 'revisionsize':
215  return (string)$parser->getRevisionSize();
216  case 'namespace':
217  return str_replace( '_', ' ',
218  $parser->getContentLanguage()->getNsText( $title->getNamespace() ) );
219  case 'namespacee':
220  return wfUrlencode( $parser->getContentLanguage()->getNsText( $title->getNamespace() ) );
221  case 'namespacenumber':
222  return $title->getNamespace();
223  case 'talkspace':
224  return $title->canHaveTalkPage()
225  ? str_replace( '_', ' ', $title->getTalkNsText() )
226  : '';
227  case 'talkspacee':
228  return $title->canHaveTalkPage()
229  ? wfUrlencode( $title->getTalkNsText() )
230  : '';
231  case 'subjectspace':
232  return str_replace( '_', ' ', $title->getSubjectNsText() );
233  case 'subjectspacee':
234  return ( wfUrlencode( $title->getSubjectNsText() ) );
235  case 'currentdayname':
236  return $pageLang->getWeekdayName( (int)MWTimestamp::getInstance( $ts )->format( 'w' ) + 1 );
237  case 'currentyear':
238  return $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'Y' ), true );
239  case 'currenttime':
240  return $pageLang->time( wfTimestamp( TS_MW, $ts ), false, false );
241  case 'currenthour':
242  return $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'H' ), true );
243  case 'currentweek':
244  // @bug T6594 PHP5 has it zero padded, PHP4 does not, cast to
245  // int to remove the padding
246  return $pageLang->formatNum( (int)MWTimestamp::getInstance( $ts )->format( 'W' ) );
247  case 'currentdow':
248  return $pageLang->formatNum( MWTimestamp::getInstance( $ts )->format( 'w' ) );
249  case 'localdayname':
250  return $pageLang->getWeekdayName(
251  (int)MWTimestamp::getLocalInstance( $ts )->format( 'w' ) + 1
252  );
253  case 'localyear':
254  return $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'Y' ), true );
255  case 'localtime':
256  return $pageLang->time(
257  MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' ),
258  false,
259  false
260  );
261  case 'localhour':
262  return $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'H' ), true );
263  case 'localweek':
264  // @bug T6594 PHP5 has it zero padded, PHP4 does not, cast to
265  // int to remove the padding
266  return $pageLang->formatNum( (int)MWTimestamp::getLocalInstance( $ts )->format( 'W' ) );
267  case 'localdow':
268  return $pageLang->formatNum( MWTimestamp::getLocalInstance( $ts )->format( 'w' ) );
269  case 'numberofarticles':
270  return $pageLang->formatNum( SiteStats::articles() );
271  case 'numberoffiles':
272  return $pageLang->formatNum( SiteStats::images() );
273  case 'numberofusers':
274  return $pageLang->formatNum( SiteStats::users() );
275  case 'numberofactiveusers':
276  return $pageLang->formatNum( SiteStats::activeUsers() );
277  case 'numberofpages':
278  return $pageLang->formatNum( SiteStats::pages() );
279  case 'numberofadmins':
280  return $pageLang->formatNum( SiteStats::numberingroup( 'sysop' ) );
281  case 'numberofedits':
282  return $pageLang->formatNum( SiteStats::edits() );
283  case 'currenttimestamp':
284  return wfTimestamp( TS_MW, $ts );
285  case 'localtimestamp':
286  return MWTimestamp::getLocalInstance( $ts )->format( 'YmdHis' );
287  case 'currentversion':
289  case 'articlepath':
290  return (string)$svcOptions->get( 'ArticlePath' );
291  case 'sitename':
292  return (string)$svcOptions->get( 'Sitename' );
293  case 'server':
294  return (string)$svcOptions->get( 'Server' );
295  case 'servername':
296  return (string)$svcOptions->get( 'ServerName' );
297  case 'scriptpath':
298  return (string)$svcOptions->get( 'ScriptPath' );
299  case 'stylepath':
300  return (string)$svcOptions->get( 'StylePath' );
301  case 'directionmark':
302  return $pageLang->getDirMark();
303  case 'contentlanguage':
304  return (string)$svcOptions->get( 'LanguageCode' );
305  case 'pagelanguage':
306  return $pageLang->getCode();
307  case 'cascadingsources':
308  return CoreParserFunctions::cascadingsources( $parser );
309  default:
310  // This is not one of the core magic words
311  return null;
312  }
313  }
314 
324  private static function getRevisionTimestampSubstring(
325  Parser $parser,
326  LoggerInterface $logger,
327  int $start,
328  int $len,
329  int $mtts,
330  string $variable
331  ): string {
332  // Get the timezone-adjusted timestamp to be used for this revision
333  $resNow = substr( $parser->getRevisionTimestamp(), $start, $len );
334  // Possibly set vary-revision if there is not yet an associated revision
335  if ( !$parser->getRevisionRecordObject() ) {
336  // Get the timezone-adjusted timestamp $mtts seconds in the future.
337  // This future is relative to the current time and not that of the
338  // parser options. The rendered timestamp can be compared to that
339  // of the timestamp specified by the parser options.
340  $resThen = substr(
341  $parser->getContentLanguage()->userAdjust( wfTimestamp( TS_MW, time() + $mtts ), '' ),
342  $start,
343  $len
344  );
345 
346  if ( $resNow !== $resThen ) {
347  // Inform the edit saving system that getting the canonical output after
348  // revision insertion requires a parse that used an actual revision timestamp
349  self::setOutputFlag( $parser, $logger, 'vary-revision-timestamp', "$variable used" );
350  }
351  }
352 
353  return $resNow;
354  }
355 
364  private static function setOutputFlag(
365  Parser $parser,
366  LoggerInterface $logger,
367  string $flag,
368  string $reason
369  ): void {
370  $parser->getOutput()->setFlag( $flag );
371  $name = $parser->getTitle()->getPrefixedText();
372  // This code was moved from Parser::setOutputFlag and used __METHOD__
373  // originally; we've hard-coded that output here so that our refactor
374  // doesn't change the messages in the logs.
375  $logger->debug( "Parser::setOutputFlag: set $flag flag on '$name'; $reason" );
376  }
377 }
SiteStats\articles
static articles()
Definition: SiteStats.php:103
SiteStats\users
static users()
Definition: SiteStats.php:121
SiteStats\activeUsers
static activeUsers()
Definition: SiteStats.php:130
Parser\getRevisionSize
getRevisionSize()
Get the size of the revision.
Definition: Parser.php:5887
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1806
SiteStats\pages
static pages()
Definition: SiteStats.php:112
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:309
SiteStats\numberingroup
static numberingroup( $group)
Find the number of users in a given user group.
Definition: SiteStats.php:150
NamespaceInfo\isSubject
isSubject( $index)
Is the given namespace is a subject (non-talk) namespace?
Definition: NamespaceInfo.php:155
CoreMagicWords\expand
static expand(Parser $parser, string $index, int $ts, NamespaceInfo $nsInfo, ServiceOptions $svcOptions, LoggerInterface $logger)
Expand the magic word given by $index.
Definition: CoreMagicWords.php:47
CoreMagicWords\getRevisionTimestampSubstring
static getRevisionTimestampSubstring(Parser $parser, LoggerInterface $logger, int $start, int $len, int $mtts, string $variable)
Definition: CoreMagicWords.php:324
Parser\getOptions
getOptions()
Definition: Parser.php:1065
SiteStats\images
static images()
Definition: SiteStats.php:139
Parser\getFunctionLang
getFunctionLang()
Get a language object for use in parser functions such as {{FORMATNUM:}}.
Definition: Parser.php:1108
Parser\getTitle
getTitle()
Definition: Parser.php:1003
Parser\getRevisionRecordObject
getRevisionRecordObject()
Get the revision record object for $this->mRevisionId.
Definition: Parser.php:5785
MediaWiki\Config\ServiceOptions
A class for passing options to services.
Definition: ServiceOptions.php:25
MWTimestamp\getInstance
static getInstance( $ts=false)
Get a timestamp instance in GMT.
Definition: MWTimestamp.php:39
$title
$title
Definition: testCompression.php:38
Parser\getContentLanguage
getContentLanguage()
Get the content language that this Parser is using.
Definition: Parser.php:1191
Parser\getRevisionUser
getRevisionUser()
Get the name of the user that edited the last revision.
Definition: Parser.php:5864
SpecialVersion\getVersion
static getVersion( $flags='', $lang=null)
Return a string of the MediaWiki version with Git revision if available.
Definition: SpecialVersion.php:310
CoreMagicWords\setOutputFlag
static setOutputFlag(Parser $parser, LoggerInterface $logger, string $flag, string $reason)
Helper method borrowed from Parser.php: sets the flag on the output but also does some debug logging.
Definition: CoreMagicWords.php:364
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1485
Parser
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition: Parser.php:82
CoreParserFunctions\cascadingsources
static cascadingsources( $parser, $title='')
Returns the sources of any cascading protection acting on a specified page.
Definition: CoreParserFunctions.php:1420
Parser\getOutput
getOutput()
Definition: Parser.php:1058
MediaWiki\Config\ServiceOptions\get
get( $key)
Definition: ServiceOptions.php:84
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:35
Parser\getRevisionTimestamp
getRevisionTimestamp()
Get the timestamp associated with the current revision, adjusted for the default server-local timesta...
Definition: Parser.php:5839
MWTimestamp\getLocalInstance
static getLocalInstance( $ts=false)
Get a timestamp instance in the server local timezone ($wgLocaltimezone)
Definition: MWTimestamp.php:203
CoreMagicWords
Expansions of core magic words, used by the parser.
Definition: CoreMagicWords.php:31
SiteStats\edits
static edits()
Definition: SiteStats.php:94
Parser\getRevisionId
getRevisionId()
Get the ID of the revision we are parsing.
Definition: Parser.php:5751