[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Parser functions provided by MediaWiki core 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 24 /** 25 * Various core parser functions, registered in Parser::firstCallInit() 26 * @ingroup Parser 27 */ 28 class CoreParserFunctions { 29 /** 30 * @param Parser $parser 31 * @return void 32 */ 33 public static function register( $parser ) { 34 global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions; 35 36 # Syntax for arguments (see Parser::setFunctionHook): 37 # "name for lookup in localized magic words array", 38 # function callback, 39 # optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}} 40 # instead of {{#int:...}}) 41 $noHashFunctions = array( 42 'ns', 'nse', 'urlencode', 'lcfirst', 'ucfirst', 'lc', 'uc', 43 'localurl', 'localurle', 'fullurl', 'fullurle', 'canonicalurl', 44 'canonicalurle', 'formatnum', 'grammar', 'gender', 'plural', 45 'numberofpages', 'numberofusers', 'numberofactiveusers', 46 'numberofarticles', 'numberoffiles', 'numberofadmins', 47 'numberingroup', 'numberofedits', 'numberofviews', 'language', 48 'padleft', 'padright', 'anchorencode', 'defaultsort', 'filepath', 49 'pagesincategory', 'pagesize', 'protectionlevel', 50 'namespacee', 'namespacenumber', 'talkspace', 'talkspacee', 51 'subjectspace', 'subjectspacee', 'pagename', 'pagenamee', 52 'fullpagename', 'fullpagenamee', 'rootpagename', 'rootpagenamee', 53 'basepagename', 'basepagenamee', 'subpagename', 'subpagenamee', 54 'talkpagename', 'talkpagenamee', 'subjectpagename', 55 'subjectpagenamee', 'pageid', 'revisionid', 'revisionday', 56 'revisionday2', 'revisionmonth', 'revisionmonth1', 'revisionyear', 57 'revisiontimestamp', 'revisionuser', 'cascadingsources', 58 ); 59 foreach ( $noHashFunctions as $func ) { 60 $parser->setFunctionHook( $func, array( __CLASS__, $func ), SFH_NO_HASH ); 61 } 62 63 $parser->setFunctionHook( 'namespace', array( __CLASS__, 'mwnamespace' ), SFH_NO_HASH ); 64 $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), SFH_NO_HASH ); 65 $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) ); 66 $parser->setFunctionHook( 'speciale', array( __CLASS__, 'speciale' ) ); 67 $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS ); 68 $parser->setFunctionHook( 'formatdate', array( __CLASS__, 'formatDate' ) ); 69 70 if ( $wgAllowDisplayTitle ) { 71 $parser->setFunctionHook( 'displaytitle', array( __CLASS__, 'displaytitle' ), SFH_NO_HASH ); 72 } 73 if ( $wgAllowSlowParserFunctions ) { 74 $parser->setFunctionHook( 75 'pagesinnamespace', 76 array( __CLASS__, 'pagesinnamespace' ), 77 SFH_NO_HASH 78 ); 79 } 80 } 81 82 /** 83 * @param Parser $parser 84 * @param string $part1 85 * @return array 86 */ 87 public static function intFunction( $parser, $part1 = '' /*, ... */ ) { 88 if ( strval( $part1 ) !== '' ) { 89 $args = array_slice( func_get_args(), 2 ); 90 $message = wfMessage( $part1, $args ) 91 ->inLanguage( $parser->getOptions()->getUserLangObj() )->plain(); 92 93 return array( $message, 'noparse' => false ); 94 } else { 95 return array( 'found' => false ); 96 } 97 } 98 99 /** 100 * @param Parser $parser 101 * @param string $date 102 * @param string $defaultPref 103 * 104 * @return string 105 */ 106 public static function formatDate( $parser, $date, $defaultPref = null ) { 107 $lang = $parser->getFunctionLang(); 108 $df = DateFormatter::getInstance( $lang ); 109 110 $date = trim( $date ); 111 112 $pref = $parser->getOptions()->getDateFormat(); 113 114 // Specify a different default date format other than the the normal default 115 // if the user has 'default' for their setting 116 if ( $pref == 'default' && $defaultPref ) { 117 $pref = $defaultPref; 118 } 119 120 $date = $df->reformat( $pref, $date, array( 'match-whole' ) ); 121 return $date; 122 } 123 124 public static function ns( $parser, $part1 = '' ) { 125 global $wgContLang; 126 if ( intval( $part1 ) || $part1 == "0" ) { 127 $index = intval( $part1 ); 128 } else { 129 $index = $wgContLang->getNsIndex( str_replace( ' ', '_', $part1 ) ); 130 } 131 if ( $index !== false ) { 132 return $wgContLang->getFormattedNsText( $index ); 133 } else { 134 return array( 'found' => false ); 135 } 136 } 137 138 public static function nse( $parser, $part1 = '' ) { 139 $ret = self::ns( $parser, $part1 ); 140 if ( is_string( $ret ) ) { 141 $ret = wfUrlencode( str_replace( ' ', '_', $ret ) ); 142 } 143 return $ret; 144 } 145 146 /** 147 * urlencodes a string according to one of three patterns: (bug 22474) 148 * 149 * By default (for HTTP "query" strings), spaces are encoded as '+'. 150 * Or to encode a value for the HTTP "path", spaces are encoded as '%20'. 151 * For links to "wiki"s, or similar software, spaces are encoded as '_', 152 * 153 * @param Parser $parser 154 * @param string $s The text to encode. 155 * @param string $arg (optional): The type of encoding. 156 * @return string 157 */ 158 public static function urlencode( $parser, $s = '', $arg = null ) { 159 static $magicWords = null; 160 if ( is_null( $magicWords ) ) { 161 $magicWords = new MagicWordArray( array( 'url_path', 'url_query', 'url_wiki' ) ); 162 } 163 switch ( $magicWords->matchStartToEnd( $arg ) ) { 164 165 // Encode as though it's a wiki page, '_' for ' '. 166 case 'url_wiki': 167 $func = 'wfUrlencode'; 168 $s = str_replace( ' ', '_', $s ); 169 break; 170 171 // Encode for an HTTP Path, '%20' for ' '. 172 case 'url_path': 173 $func = 'rawurlencode'; 174 break; 175 176 // Encode for HTTP query, '+' for ' '. 177 case 'url_query': 178 default: 179 $func = 'urlencode'; 180 } 181 return $parser->markerSkipCallback( $s, $func ); 182 } 183 184 public static function lcfirst( $parser, $s = '' ) { 185 global $wgContLang; 186 return $wgContLang->lcfirst( $s ); 187 } 188 189 public static function ucfirst( $parser, $s = '' ) { 190 global $wgContLang; 191 return $wgContLang->ucfirst( $s ); 192 } 193 194 /** 195 * @param Parser $parser 196 * @param string $s 197 * @return string 198 */ 199 public static function lc( $parser, $s = '' ) { 200 global $wgContLang; 201 return $parser->markerSkipCallback( $s, array( $wgContLang, 'lc' ) ); 202 } 203 204 /** 205 * @param Parser $parser 206 * @param string $s 207 * @return string 208 */ 209 public static function uc( $parser, $s = '' ) { 210 global $wgContLang; 211 return $parser->markerSkipCallback( $s, array( $wgContLang, 'uc' ) ); 212 } 213 214 public static function localurl( $parser, $s = '', $arg = null ) { 215 return self::urlFunction( 'getLocalURL', $s, $arg ); 216 } 217 218 public static function localurle( $parser, $s = '', $arg = null ) { 219 $temp = self::urlFunction( 'getLocalURL', $s, $arg ); 220 if ( !is_string( $temp ) ) { 221 return $temp; 222 } else { 223 return htmlspecialchars( $temp ); 224 } 225 } 226 227 public static function fullurl( $parser, $s = '', $arg = null ) { 228 return self::urlFunction( 'getFullURL', $s, $arg ); 229 } 230 231 public static function fullurle( $parser, $s = '', $arg = null ) { 232 $temp = self::urlFunction( 'getFullURL', $s, $arg ); 233 if ( !is_string( $temp ) ) { 234 return $temp; 235 } else { 236 return htmlspecialchars( $temp ); 237 } 238 } 239 240 public static function canonicalurl( $parser, $s = '', $arg = null ) { 241 return self::urlFunction( 'getCanonicalURL', $s, $arg ); 242 } 243 244 public static function canonicalurle( $parser, $s = '', $arg = null ) { 245 $temp = self::urlFunction( 'getCanonicalURL', $s, $arg ); 246 if ( !is_string( $temp ) ) { 247 return $temp; 248 } else { 249 return htmlspecialchars( $temp ); 250 } 251 } 252 253 public static function urlFunction( $func, $s = '', $arg = null ) { 254 $title = Title::newFromText( $s ); 255 # Due to order of execution of a lot of bits, the values might be encoded 256 # before arriving here; if that's true, then the title can't be created 257 # and the variable will fail. If we can't get a decent title from the first 258 # attempt, url-decode and try for a second. 259 if ( is_null( $title ) ) { 260 $title = Title::newFromURL( urldecode( $s ) ); 261 } 262 if ( !is_null( $title ) ) { 263 # Convert NS_MEDIA -> NS_FILE 264 if ( $title->getNamespace() == NS_MEDIA ) { 265 $title = Title::makeTitle( NS_FILE, $title->getDBkey() ); 266 } 267 if ( !is_null( $arg ) ) { 268 $text = $title->$func( $arg ); 269 } else { 270 $text = $title->$func(); 271 } 272 return $text; 273 } else { 274 return array( 'found' => false ); 275 } 276 } 277 278 /** 279 * @param Parser $parser 280 * @param string $num 281 * @param string $arg 282 * @return string 283 */ 284 public static function formatnum( $parser, $num = '', $arg = null ) { 285 if ( self::matchAgainstMagicword( 'rawsuffix', $arg ) ) { 286 $func = array( $parser->getFunctionLang(), 'parseFormattedNumber' ); 287 } elseif ( self::matchAgainstMagicword( 'nocommafysuffix', $arg ) ) { 288 $func = array( $parser->getFunctionLang(), 'formatNumNoSeparators' ); 289 } else { 290 $func = array( $parser->getFunctionLang(), 'formatNum' ); 291 } 292 return $parser->markerSkipCallback( $num, $func ); 293 } 294 295 /** 296 * @param Parser $parser 297 * @param string $case 298 * @param string $word 299 * @return string 300 */ 301 public static function grammar( $parser, $case = '', $word = '' ) { 302 $word = $parser->killMarkers( $word ); 303 return $parser->getFunctionLang()->convertGrammar( $word, $case ); 304 } 305 306 /** 307 * @param Parser $parser 308 * @param string $username 309 * @return string 310 */ 311 public static function gender( $parser, $username ) { 312 wfProfileIn( __METHOD__ ); 313 $forms = array_slice( func_get_args(), 2 ); 314 315 // Some shortcuts to avoid loading user data unnecessarily 316 if ( count( $forms ) === 0 ) { 317 wfProfileOut( __METHOD__ ); 318 return ''; 319 } elseif ( count( $forms ) === 1 ) { 320 wfProfileOut( __METHOD__ ); 321 return $forms[0]; 322 } 323 324 $username = trim( $username ); 325 326 // default 327 $gender = User::getDefaultOption( 'gender' ); 328 329 // allow prefix. 330 $title = Title::newFromText( $username ); 331 332 if ( $title && $title->getNamespace() == NS_USER ) { 333 $username = $title->getText(); 334 } 335 336 // check parameter, or use the ParserOptions if in interface message 337 $user = User::newFromName( $username ); 338 if ( $user ) { 339 $gender = GenderCache::singleton()->getGenderOf( $user, __METHOD__ ); 340 } elseif ( $username === '' && $parser->getOptions()->getInterfaceMessage() ) { 341 $gender = GenderCache::singleton()->getGenderOf( $parser->getOptions()->getUser(), __METHOD__ ); 342 } 343 $ret = $parser->getFunctionLang()->gender( $gender, $forms ); 344 wfProfileOut( __METHOD__ ); 345 return $ret; 346 } 347 348 /** 349 * @param Parser $parser 350 * @param string $text 351 * @return string 352 */ 353 public static function plural( $parser, $text = '' ) { 354 $forms = array_slice( func_get_args(), 2 ); 355 $text = $parser->getFunctionLang()->parseFormattedNumber( $text ); 356 settype( $text, ctype_digit( $text ) ? 'int' : 'float' ); 357 return $parser->getFunctionLang()->convertPlural( $text, $forms ); 358 } 359 360 /** 361 * Override the title of the page when viewed, provided we've been given a 362 * title which will normalise to the canonical title 363 * 364 * @param Parser $parser Parent parser 365 * @param string $text Desired title text 366 * @param string $uarg 367 * @return string 368 */ 369 public static function displaytitle( $parser, $text = '', $uarg = '' ) { 370 global $wgRestrictDisplayTitle; 371 372 static $magicWords = null; 373 if ( is_null( $magicWords ) ) { 374 $magicWords = new MagicWordArray( array( 'displaytitle_noerror', 'displaytitle_noreplace' ) ); 375 } 376 $arg = $magicWords->matchStartToEnd( $uarg ); 377 378 // parse a limited subset of wiki markup (just the single quote items) 379 $text = $parser->doQuotes( $text ); 380 381 // remove stripped text (e.g. the UNIQ-QINU stuff) that was generated by tag extensions/whatever 382 $text = preg_replace( '/' . preg_quote( $parser->uniqPrefix(), '/' ) . '.*?' 383 . preg_quote( Parser::MARKER_SUFFIX, '/' ) . '/', '', $text ); 384 385 // list of disallowed tags for DISPLAYTITLE 386 // these will be escaped even though they are allowed in normal wiki text 387 $bad = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr', 388 'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rtc', 'rp', 'br' ); 389 390 // disallow some styles that could be used to bypass $wgRestrictDisplayTitle 391 if ( $wgRestrictDisplayTitle ) { 392 $htmlTagsCallback = function ( &$params ) { 393 $decoded = Sanitizer::decodeTagAttributes( $params ); 394 395 if ( isset( $decoded['style'] ) ) { 396 // this is called later anyway, but we need it right now for the regexes below to be safe 397 // calling it twice doesn't hurt 398 $decoded['style'] = Sanitizer::checkCss( $decoded['style'] ); 399 400 if ( preg_match( '/(display|user-select|visibility)\s*:/i', $decoded['style'] ) ) { 401 $decoded['style'] = '/* attempt to bypass $wgRestrictDisplayTitle */'; 402 } 403 } 404 405 $params = Sanitizer::safeEncodeTagAttributes( $decoded ); 406 }; 407 } else { 408 $htmlTagsCallback = null; 409 } 410 411 // only requested titles that normalize to the actual title are allowed through 412 // if $wgRestrictDisplayTitle is true (it is by default) 413 // mimic the escaping process that occurs in OutputPage::setPageTitle 414 $text = Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags( 415 $text, 416 $htmlTagsCallback, 417 array(), 418 array(), 419 $bad 420 ) ); 421 $title = Title::newFromText( Sanitizer::stripAllTags( $text ) ); 422 423 if ( !$wgRestrictDisplayTitle || 424 ( $title instanceof Title 425 && !$title->hasFragment() 426 && $title->equals( $parser->mTitle ) ) 427 ) { 428 $old = $parser->mOutput->getProperty( 'displaytitle' ); 429 if ( $old === false || $arg !== 'displaytitle_noreplace' ) { 430 $parser->mOutput->setDisplayTitle( $text ); 431 } 432 if ( $old !== false && $old !== $text && !$arg ) { 433 $converter = $parser->getConverterLanguage()->getConverter(); 434 return '<span class="error">' . 435 wfMessage( 'duplicate-displaytitle', 436 // Message should be parsed, but these params should only be escaped. 437 $converter->markNoConversion( wfEscapeWikiText( $old ) ), 438 $converter->markNoConversion( wfEscapeWikiText( $text ) ) 439 )->inContentLanguage()->text() . 440 '</span>'; 441 } 442 } 443 444 return ''; 445 } 446 447 /** 448 * Matches the given value against the value of given magic word 449 * 450 * @param string $magicword Magic word key 451 * @param string $value Value to match 452 * @return bool True on successful match 453 */ 454 private static function matchAgainstMagicword( $magicword, $value ) { 455 $value = trim( strval( $value ) ); 456 if ( $value === '' ) { 457 return false; 458 } 459 $mwObject = MagicWord::get( $magicword ); 460 return $mwObject->matchStartToEnd( $value ); 461 } 462 463 public static function formatRaw( $num, $raw ) { 464 if ( self::matchAgainstMagicword( 'rawsuffix', $raw ) ) { 465 return $num; 466 } else { 467 global $wgContLang; 468 return $wgContLang->formatNum( $num ); 469 } 470 } 471 public static function numberofpages( $parser, $raw = null ) { 472 return self::formatRaw( SiteStats::pages(), $raw ); 473 } 474 public static function numberofusers( $parser, $raw = null ) { 475 return self::formatRaw( SiteStats::users(), $raw ); 476 } 477 public static function numberofactiveusers( $parser, $raw = null ) { 478 return self::formatRaw( SiteStats::activeUsers(), $raw ); 479 } 480 public static function numberofarticles( $parser, $raw = null ) { 481 return self::formatRaw( SiteStats::articles(), $raw ); 482 } 483 public static function numberoffiles( $parser, $raw = null ) { 484 return self::formatRaw( SiteStats::images(), $raw ); 485 } 486 public static function numberofadmins( $parser, $raw = null ) { 487 return self::formatRaw( SiteStats::numberingroup( 'sysop' ), $raw ); 488 } 489 public static function numberofedits( $parser, $raw = null ) { 490 return self::formatRaw( SiteStats::edits(), $raw ); 491 } 492 public static function numberofviews( $parser, $raw = null ) { 493 global $wgDisableCounters; 494 return !$wgDisableCounters ? self::formatRaw( SiteStats::views(), $raw ) : ''; 495 } 496 public static function pagesinnamespace( $parser, $namespace = 0, $raw = null ) { 497 return self::formatRaw( SiteStats::pagesInNs( intval( $namespace ) ), $raw ); 498 } 499 public static function numberingroup( $parser, $name = '', $raw = null ) { 500 return self::formatRaw( SiteStats::numberingroup( strtolower( $name ) ), $raw ); 501 } 502 503 /** 504 * Given a title, return the namespace name that would be given by the 505 * corresponding magic word 506 * Note: function name changed to "mwnamespace" rather than "namespace" 507 * to not break PHP 5.3 508 * @param Parser $parser 509 * @param string $title 510 * @return mixed|string 511 */ 512 public static function mwnamespace( $parser, $title = null ) { 513 $t = Title::newFromText( $title ); 514 if ( is_null( $t ) ) { 515 return ''; 516 } 517 return str_replace( '_', ' ', $t->getNsText() ); 518 } 519 public static function namespacee( $parser, $title = null ) { 520 $t = Title::newFromText( $title ); 521 if ( is_null( $t ) ) { 522 return ''; 523 } 524 return wfUrlencode( $t->getNsText() ); 525 } 526 public static function namespacenumber( $parser, $title = null ) { 527 $t = Title::newFromText( $title ); 528 if ( is_null( $t ) ) { 529 return ''; 530 } 531 return $t->getNamespace(); 532 } 533 public static function talkspace( $parser, $title = null ) { 534 $t = Title::newFromText( $title ); 535 if ( is_null( $t ) || !$t->canTalk() ) { 536 return ''; 537 } 538 return str_replace( '_', ' ', $t->getTalkNsText() ); 539 } 540 public static function talkspacee( $parser, $title = null ) { 541 $t = Title::newFromText( $title ); 542 if ( is_null( $t ) || !$t->canTalk() ) { 543 return ''; 544 } 545 return wfUrlencode( $t->getTalkNsText() ); 546 } 547 public static function subjectspace( $parser, $title = null ) { 548 $t = Title::newFromText( $title ); 549 if ( is_null( $t ) ) { 550 return ''; 551 } 552 return str_replace( '_', ' ', $t->getSubjectNsText() ); 553 } 554 public static function subjectspacee( $parser, $title = null ) { 555 $t = Title::newFromText( $title ); 556 if ( is_null( $t ) ) { 557 return ''; 558 } 559 return wfUrlencode( $t->getSubjectNsText() ); 560 } 561 562 /** 563 * Functions to get and normalize pagenames, corresponding to the magic words 564 * of the same names 565 * @param Parser $parser 566 * @param string $title 567 * @return string 568 */ 569 public static function pagename( $parser, $title = null ) { 570 $t = Title::newFromText( $title ); 571 if ( is_null( $t ) ) { 572 return ''; 573 } 574 return wfEscapeWikiText( $t->getText() ); 575 } 576 public static function pagenamee( $parser, $title = null ) { 577 $t = Title::newFromText( $title ); 578 if ( is_null( $t ) ) { 579 return ''; 580 } 581 return wfEscapeWikiText( $t->getPartialURL() ); 582 } 583 public static function fullpagename( $parser, $title = null ) { 584 $t = Title::newFromText( $title ); 585 if ( is_null( $t ) || !$t->canTalk() ) { 586 return ''; 587 } 588 return wfEscapeWikiText( $t->getPrefixedText() ); 589 } 590 public static function fullpagenamee( $parser, $title = null ) { 591 $t = Title::newFromText( $title ); 592 if ( is_null( $t ) || !$t->canTalk() ) { 593 return ''; 594 } 595 return wfEscapeWikiText( $t->getPrefixedURL() ); 596 } 597 public static function subpagename( $parser, $title = null ) { 598 $t = Title::newFromText( $title ); 599 if ( is_null( $t ) ) { 600 return ''; 601 } 602 return wfEscapeWikiText( $t->getSubpageText() ); 603 } 604 public static function subpagenamee( $parser, $title = null ) { 605 $t = Title::newFromText( $title ); 606 if ( is_null( $t ) ) { 607 return ''; 608 } 609 return wfEscapeWikiText( $t->getSubpageUrlForm() ); 610 } 611 public static function rootpagename( $parser, $title = null ) { 612 $t = Title::newFromText( $title ); 613 if ( is_null( $t ) ) { 614 return ''; 615 } 616 return wfEscapeWikiText( $t->getRootText() ); 617 } 618 public static function rootpagenamee( $parser, $title = null ) { 619 $t = Title::newFromText( $title ); 620 if ( is_null( $t ) ) { 621 return ''; 622 } 623 return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getRootText() ) ) ); 624 } 625 public static function basepagename( $parser, $title = null ) { 626 $t = Title::newFromText( $title ); 627 if ( is_null( $t ) ) { 628 return ''; 629 } 630 return wfEscapeWikiText( $t->getBaseText() ); 631 } 632 public static function basepagenamee( $parser, $title = null ) { 633 $t = Title::newFromText( $title ); 634 if ( is_null( $t ) ) { 635 return ''; 636 } 637 return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getBaseText() ) ) ); 638 } 639 public static function talkpagename( $parser, $title = null ) { 640 $t = Title::newFromText( $title ); 641 if ( is_null( $t ) || !$t->canTalk() ) { 642 return ''; 643 } 644 return wfEscapeWikiText( $t->getTalkPage()->getPrefixedText() ); 645 } 646 public static function talkpagenamee( $parser, $title = null ) { 647 $t = Title::newFromText( $title ); 648 if ( is_null( $t ) || !$t->canTalk() ) { 649 return ''; 650 } 651 return wfEscapeWikiText( $t->getTalkPage()->getPrefixedURL() ); 652 } 653 public static function subjectpagename( $parser, $title = null ) { 654 $t = Title::newFromText( $title ); 655 if ( is_null( $t ) ) { 656 return ''; 657 } 658 return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedText() ); 659 } 660 public static function subjectpagenamee( $parser, $title = null ) { 661 $t = Title::newFromText( $title ); 662 if ( is_null( $t ) ) { 663 return ''; 664 } 665 return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedURL() ); 666 } 667 668 /** 669 * Return the number of pages, files or subcats in the given category, 670 * or 0 if it's nonexistent. This is an expensive parser function and 671 * can't be called too many times per page. 672 * @param Parser $parser 673 * @param string $name 674 * @param string $arg1 675 * @param string $arg2 676 * @return string 677 */ 678 public static function pagesincategory( $parser, $name = '', $arg1 = null, $arg2 = null ) { 679 global $wgContLang; 680 static $magicWords = null; 681 if ( is_null( $magicWords ) ) { 682 $magicWords = new MagicWordArray( array( 683 'pagesincategory_all', 684 'pagesincategory_pages', 685 'pagesincategory_subcats', 686 'pagesincategory_files' 687 ) ); 688 } 689 static $cache = array(); 690 691 // split the given option to its variable 692 if ( self::matchAgainstMagicword( 'rawsuffix', $arg1 ) ) { 693 //{{pagesincategory:|raw[|type]}} 694 $raw = $arg1; 695 $type = $magicWords->matchStartToEnd( $arg2 ); 696 } else { 697 //{{pagesincategory:[|type[|raw]]}} 698 $type = $magicWords->matchStartToEnd( $arg1 ); 699 $raw = $arg2; 700 } 701 if ( !$type ) { //backward compatibility 702 $type = 'pagesincategory_all'; 703 } 704 705 $title = Title::makeTitleSafe( NS_CATEGORY, $name ); 706 if ( !$title ) { # invalid title 707 return self::formatRaw( 0, $raw ); 708 } 709 $wgContLang->findVariantLink( $name, $title, true ); 710 711 // Normalize name for cache 712 $name = $title->getDBkey(); 713 714 if ( !isset( $cache[$name] ) ) { 715 $category = Category::newFromTitle( $title ); 716 717 $allCount = $subcatCount = $fileCount = $pagesCount = 0; 718 if ( $parser->incrementExpensiveFunctionCount() ) { 719 // $allCount is the total number of cat members, 720 // not the count of how many members are normal pages. 721 $allCount = (int)$category->getPageCount(); 722 $subcatCount = (int)$category->getSubcatCount(); 723 $fileCount = (int)$category->getFileCount(); 724 $pagesCount = $allCount - $subcatCount - $fileCount; 725 } 726 $cache[$name]['pagesincategory_all'] = $allCount; 727 $cache[$name]['pagesincategory_pages'] = $pagesCount; 728 $cache[$name]['pagesincategory_subcats'] = $subcatCount; 729 $cache[$name]['pagesincategory_files'] = $fileCount; 730 } 731 732 $count = $cache[$name][$type]; 733 return self::formatRaw( $count, $raw ); 734 } 735 736 /** 737 * Return the size of the given page, or 0 if it's nonexistent. This is an 738 * expensive parser function and can't be called too many times per page. 739 * 740 * @param Parser $parser 741 * @param string $page Name of page to check (Default: empty string) 742 * @param string $raw Should number be human readable with commas or just number 743 * @return string 744 */ 745 public static function pagesize( $parser, $page = '', $raw = null ) { 746 $title = Title::newFromText( $page ); 747 748 if ( !is_object( $title ) ) { 749 return self::formatRaw( 0, $raw ); 750 } 751 752 // fetch revision from cache/database and return the value 753 $rev = self::getCachedRevisionObject( $parser, $title ); 754 $length = $rev ? $rev->getSize() : 0; 755 return self::formatRaw( $length, $raw ); 756 } 757 758 /** 759 * Returns the requested protection level for the current page. This 760 * is an expensive parser function and can't be called too many times 761 * per page, unless the protection levels for the given title have 762 * already been retrieved 763 * 764 * @param Parser $parser 765 * @param string $type 766 * @param string $title 767 * 768 * @return string 769 */ 770 public static function protectionlevel( $parser, $type = '', $title = '' ) { 771 $titleObject = Title::newFromText( $title ); 772 if ( !( $titleObject instanceof Title ) ) { 773 $titleObject = $parser->mTitle; 774 } 775 if ( $titleObject->areRestrictionsLoaded() || $parser->incrementExpensiveFunctionCount() ) { 776 $restrictions = $titleObject->getRestrictions( strtolower( $type ) ); 777 # Title::getRestrictions returns an array, its possible it may have 778 # multiple values in the future 779 return implode( $restrictions, ',' ); 780 } 781 return ''; 782 } 783 784 /** 785 * Gives language names. 786 * @param Parser $parser 787 * @param string $code Language code (of which to get name) 788 * @param string $inLanguage Language code (in which to get name) 789 * @return string 790 */ 791 public static function language( $parser, $code = '', $inLanguage = '' ) { 792 $code = strtolower( $code ); 793 $inLanguage = strtolower( $inLanguage ); 794 $lang = Language::fetchLanguageName( $code, $inLanguage ); 795 return $lang !== '' ? $lang : wfBCP47( $code ); 796 } 797 798 /** 799 * Unicode-safe str_pad with the restriction that $length is forced to be <= 500 800 * @param Parser $parser 801 * @param string $string 802 * @param int $length 803 * @param string $padding 804 * @param int $direction 805 * @return string 806 */ 807 public static function pad( $parser, $string, $length, $padding = '0', $direction = STR_PAD_RIGHT ) { 808 $padding = $parser->killMarkers( $padding ); 809 $lengthOfPadding = mb_strlen( $padding ); 810 if ( $lengthOfPadding == 0 ) { 811 return $string; 812 } 813 814 # The remaining length to add counts down to 0 as padding is added 815 $length = min( $length, 500 ) - mb_strlen( $string ); 816 # $finalPadding is just $padding repeated enough times so that 817 # mb_strlen( $string ) + mb_strlen( $finalPadding ) == $length 818 $finalPadding = ''; 819 while ( $length > 0 ) { 820 # If $length < $lengthofPadding, truncate $padding so we get the 821 # exact length desired. 822 $finalPadding .= mb_substr( $padding, 0, $length ); 823 $length -= $lengthOfPadding; 824 } 825 826 if ( $direction == STR_PAD_LEFT ) { 827 return $finalPadding . $string; 828 } else { 829 return $string . $finalPadding; 830 } 831 } 832 833 public static function padleft( $parser, $string = '', $length = 0, $padding = '0' ) { 834 return self::pad( $parser, $string, $length, $padding, STR_PAD_LEFT ); 835 } 836 837 public static function padright( $parser, $string = '', $length = 0, $padding = '0' ) { 838 return self::pad( $parser, $string, $length, $padding ); 839 } 840 841 /** 842 * @param Parser $parser 843 * @param string $text 844 * @return string 845 */ 846 public static function anchorencode( $parser, $text ) { 847 $text = $parser->killMarkers( $text ); 848 return (string)substr( $parser->guessSectionNameFromWikiText( $text ), 1 ); 849 } 850 851 public static function special( $parser, $text ) { 852 list( $page, $subpage ) = SpecialPageFactory::resolveAlias( $text ); 853 if ( $page ) { 854 $title = SpecialPage::getTitleFor( $page, $subpage ); 855 return $title->getPrefixedText(); 856 } else { 857 // unknown special page, just use the given text as its title, if at all possible 858 $title = Title::makeTitleSafe( NS_SPECIAL, $text ); 859 return $title ? $title->getPrefixedText() : self::special( $parser, 'Badtitle' ); 860 } 861 } 862 863 public static function speciale( $parser, $text ) { 864 return wfUrlencode( str_replace( ' ', '_', self::special( $parser, $text ) ) ); 865 } 866 867 /** 868 * @param Parser $parser 869 * @param string $text The sortkey to use 870 * @param string $uarg Either "noreplace" or "noerror" (in en) 871 * both suppress errors, and noreplace does nothing if 872 * a default sortkey already exists. 873 * @return string 874 */ 875 public static function defaultsort( $parser, $text, $uarg = '' ) { 876 static $magicWords = null; 877 if ( is_null( $magicWords ) ) { 878 $magicWords = new MagicWordArray( array( 'defaultsort_noerror', 'defaultsort_noreplace' ) ); 879 } 880 $arg = $magicWords->matchStartToEnd( $uarg ); 881 882 $text = trim( $text ); 883 if ( strlen( $text ) == 0 ) { 884 return ''; 885 } 886 $old = $parser->getCustomDefaultSort(); 887 if ( $old === false || $arg !== 'defaultsort_noreplace' ) { 888 $parser->setDefaultSort( $text ); 889 } 890 891 if ( $old === false || $old == $text || $arg ) { 892 return ''; 893 } else { 894 $converter = $parser->getConverterLanguage()->getConverter(); 895 return '<span class="error">' . 896 wfMessage( 'duplicate-defaultsort', 897 // Message should be parsed, but these params should only be escaped. 898 $converter->markNoConversion( wfEscapeWikiText( $old ) ), 899 $converter->markNoConversion( wfEscapeWikiText( $text ) ) 900 )->inContentLanguage()->text() . 901 '</span>'; 902 } 903 } 904 905 // Usage {{filepath|300}}, {{filepath|nowiki}}, {{filepath|nowiki|300}} 906 // or {{filepath|300|nowiki}} or {{filepath|300px}}, {{filepath|200x300px}}, 907 // {{filepath|nowiki|200x300px}}, {{filepath|200x300px|nowiki}}. 908 public static function filepath( $parser, $name = '', $argA = '', $argB = '' ) { 909 $file = wfFindFile( $name ); 910 911 if ( $argA == 'nowiki' ) { 912 // {{filepath: | option [| size] }} 913 $isNowiki = true; 914 $parsedWidthParam = $parser->parseWidthParam( $argB ); 915 } else { 916 // {{filepath: [| size [|option]] }} 917 $parsedWidthParam = $parser->parseWidthParam( $argA ); 918 $isNowiki = ( $argB == 'nowiki' ); 919 } 920 921 if ( $file ) { 922 $url = $file->getFullUrl(); 923 924 // If a size is requested... 925 if ( count( $parsedWidthParam ) ) { 926 $mto = $file->transform( $parsedWidthParam ); 927 // ... and we can 928 if ( $mto && !$mto->isError() ) { 929 // ... change the URL to point to a thumbnail. 930 $url = wfExpandUrl( $mto->getUrl(), PROTO_RELATIVE ); 931 } 932 } 933 if ( $isNowiki ) { 934 return array( $url, 'nowiki' => true ); 935 } 936 return $url; 937 } else { 938 return ''; 939 } 940 } 941 942 /** 943 * Parser function to extension tag adaptor 944 * @param Parser $parser 945 * @param PPFrame $frame 946 * @param array $args 947 * @return string 948 */ 949 public static function tagObj( $parser, $frame, $args ) { 950 if ( !count( $args ) ) { 951 return ''; 952 } 953 $tagName = strtolower( trim( $frame->expand( array_shift( $args ) ) ) ); 954 955 if ( count( $args ) ) { 956 $inner = $frame->expand( array_shift( $args ) ); 957 } else { 958 $inner = null; 959 } 960 961 $stripList = $parser->getStripList(); 962 if ( !in_array( $tagName, $stripList ) ) { 963 return '<span class="error">' . 964 wfMessage( 'unknown_extension_tag', $tagName )->inContentLanguage()->text() . 965 '</span>'; 966 } 967 968 $attributes = array(); 969 foreach ( $args as $arg ) { 970 $bits = $arg->splitArg(); 971 if ( strval( $bits['index'] ) === '' ) { 972 $name = trim( $frame->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) ); 973 $value = trim( $frame->expand( $bits['value'] ) ); 974 if ( preg_match( '/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m ) ) { 975 $value = isset( $m[1] ) ? $m[1] : ''; 976 } 977 $attributes[$name] = $value; 978 } 979 } 980 981 $params = array( 982 'name' => $tagName, 983 'inner' => $inner, 984 'attributes' => $attributes, 985 'close' => "</$tagName>", 986 ); 987 return $parser->extensionSubstitution( $params, $frame ); 988 } 989 990 /** 991 * Fetched the current revision of the given title and return this. 992 * Will increment the expensive function count and 993 * add a template link to get the value refreshed on changes. 994 * For a given title, which is equal to the current parser title, 995 * the revision object from the parser is used, when that is the current one 996 * 997 * @param Parser $parser 998 * @param Title $title 999 * @return Revision 1000 * @since 1.23 1001 */ 1002 private static function getCachedRevisionObject( $parser, $title = null ) { 1003 static $cache = null; 1004 if ( $cache == null ) { 1005 $cache = new MapCacheLRU( 50 ); 1006 } 1007 1008 if ( is_null( $title ) ) { 1009 return null; 1010 } 1011 1012 // Use the revision from the parser itself, when param is the current page 1013 // and the revision is the current one 1014 if ( $title->equals( $parser->getTitle() ) ) { 1015 $parserRev = $parser->getRevisionObject(); 1016 if ( $parserRev && $parserRev->isCurrent() ) { 1017 // force reparse after edit with vary-revision flag 1018 $parser->getOutput()->setFlag( 'vary-revision' ); 1019 wfDebug( __METHOD__ . ": use current revision from parser, setting vary-revision...\n" ); 1020 return $parserRev; 1021 } 1022 } 1023 1024 // Normalize name for cache 1025 $page = $title->getPrefixedDBkey(); 1026 1027 if ( $cache->has( $page ) ) { // cache contains null values 1028 return $cache->get( $page ); 1029 } 1030 if ( $parser->incrementExpensiveFunctionCount() ) { 1031 $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL ); 1032 $pageID = $rev ? $rev->getPage() : 0; 1033 $revID = $rev ? $rev->getId() : 0; 1034 $cache->set( $page, $rev ); // maybe null 1035 1036 // Register dependency in templatelinks 1037 $parser->getOutput()->addTemplate( $title, $pageID, $revID ); 1038 1039 return $rev; 1040 } 1041 $cache->set( $page, null ); 1042 return null; 1043 } 1044 1045 /** 1046 * Get the pageid of a specified page 1047 * @param Parser $parser 1048 * @param string $title Title to get the pageid from 1049 * @return int|null|string 1050 * @since 1.23 1051 */ 1052 public static function pageid( $parser, $title = null ) { 1053 $t = Title::newFromText( $title ); 1054 if ( is_null( $t ) ) { 1055 return ''; 1056 } 1057 // Use title from parser to have correct pageid after edit 1058 if ( $t->equals( $parser->getTitle() ) ) { 1059 $t = $parser->getTitle(); 1060 return $t->getArticleID(); 1061 } 1062 1063 // These can't have ids 1064 if ( !$t->canExist() || $t->isExternal() ) { 1065 return 0; 1066 } 1067 1068 // Check the link cache, maybe something already looked it up. 1069 $linkCache = LinkCache::singleton(); 1070 $pdbk = $t->getPrefixedDBkey(); 1071 $id = $linkCache->getGoodLinkID( $pdbk ); 1072 if ( $id != 0 ) { 1073 $parser->mOutput->addLink( $t, $id ); 1074 return $id; 1075 } 1076 if ( $linkCache->isBadLink( $pdbk ) ) { 1077 $parser->mOutput->addLink( $t, 0 ); 1078 return $id; 1079 } 1080 1081 // We need to load it from the DB, so mark expensive 1082 if ( $parser->incrementExpensiveFunctionCount() ) { 1083 $id = $t->getArticleID(); 1084 $parser->mOutput->addLink( $t, $id ); 1085 return $id; 1086 } 1087 return null; 1088 } 1089 1090 /** 1091 * Get the id from the last revision of a specified page. 1092 * @param Parser $parser 1093 * @param string $title Title to get the id from 1094 * @return int|null|string 1095 * @since 1.23 1096 */ 1097 public static function revisionid( $parser, $title = null ) { 1098 $t = Title::newFromText( $title ); 1099 if ( is_null( $t ) ) { 1100 return ''; 1101 } 1102 // fetch revision from cache/database and return the value 1103 $rev = self::getCachedRevisionObject( $parser, $t ); 1104 return $rev ? $rev->getId() : ''; 1105 } 1106 1107 /** 1108 * Get the day from the last revision of a specified page. 1109 * @param Parser $parser 1110 * @param string $title Title to get the day from 1111 * @return string 1112 * @since 1.23 1113 */ 1114 public static function revisionday( $parser, $title = null ) { 1115 $t = Title::newFromText( $title ); 1116 if ( is_null( $t ) ) { 1117 return ''; 1118 } 1119 // fetch revision from cache/database and return the value 1120 $rev = self::getCachedRevisionObject( $parser, $t ); 1121 return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'j' ) : ''; 1122 } 1123 1124 /** 1125 * Get the day with leading zeros from the last revision of a specified page. 1126 * @param Parser $parser 1127 * @param string $title Title to get the day from 1128 * @return string 1129 * @since 1.23 1130 */ 1131 public static function revisionday2( $parser, $title = null ) { 1132 $t = Title::newFromText( $title ); 1133 if ( is_null( $t ) ) { 1134 return ''; 1135 } 1136 // fetch revision from cache/database and return the value 1137 $rev = self::getCachedRevisionObject( $parser, $t ); 1138 return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'd' ) : ''; 1139 } 1140 1141 /** 1142 * Get the month with leading zeros from the last revision of a specified page. 1143 * @param Parser $parser 1144 * @param string $title Title to get the month from 1145 * @return string 1146 * @since 1.23 1147 */ 1148 public static function revisionmonth( $parser, $title = null ) { 1149 $t = Title::newFromText( $title ); 1150 if ( is_null( $t ) ) { 1151 return ''; 1152 } 1153 // fetch revision from cache/database and return the value 1154 $rev = self::getCachedRevisionObject( $parser, $t ); 1155 return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'm' ) : ''; 1156 } 1157 1158 /** 1159 * Get the month from the last revision of a specified page. 1160 * @param Parser $parser 1161 * @param string $title Title to get the month from 1162 * @return string 1163 * @since 1.23 1164 */ 1165 public static function revisionmonth1( $parser, $title = null ) { 1166 $t = Title::newFromText( $title ); 1167 if ( is_null( $t ) ) { 1168 return ''; 1169 } 1170 // fetch revision from cache/database and return the value 1171 $rev = self::getCachedRevisionObject( $parser, $t ); 1172 return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'n' ) : ''; 1173 } 1174 1175 /** 1176 * Get the year from the last revision of a specified page. 1177 * @param Parser $parser 1178 * @param string $title Title to get the year from 1179 * @return string 1180 * @since 1.23 1181 */ 1182 public static function revisionyear( $parser, $title = null ) { 1183 $t = Title::newFromText( $title ); 1184 if ( is_null( $t ) ) { 1185 return ''; 1186 } 1187 // fetch revision from cache/database and return the value 1188 $rev = self::getCachedRevisionObject( $parser, $t ); 1189 return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'Y' ) : ''; 1190 } 1191 1192 /** 1193 * Get the timestamp from the last revision of a specified page. 1194 * @param Parser $parser 1195 * @param string $title Title to get the timestamp from 1196 * @return string 1197 * @since 1.23 1198 */ 1199 public static function revisiontimestamp( $parser, $title = null ) { 1200 $t = Title::newFromText( $title ); 1201 if ( is_null( $t ) ) { 1202 return ''; 1203 } 1204 // fetch revision from cache/database and return the value 1205 $rev = self::getCachedRevisionObject( $parser, $t ); 1206 return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'YmdHis' ) : ''; 1207 } 1208 1209 /** 1210 * Get the user from the last revision of a specified page. 1211 * @param Parser $parser 1212 * @param string $title Title to get the user from 1213 * @return string 1214 * @since 1.23 1215 */ 1216 public static function revisionuser( $parser, $title = null ) { 1217 $t = Title::newFromText( $title ); 1218 if ( is_null( $t ) ) { 1219 return ''; 1220 } 1221 // fetch revision from cache/database and return the value 1222 $rev = self::getCachedRevisionObject( $parser, $t ); 1223 return $rev ? $rev->getUserText() : ''; 1224 } 1225 1226 /** 1227 * Returns the sources of any cascading protection acting on a specified page. 1228 * Pages will not return their own title unless they transclude themselves. 1229 * This is an expensive parser function and can't be called too many times per page, 1230 * unless cascading protection sources for the page have already been loaded. 1231 * 1232 * @param Parser $parser 1233 * @param string $title 1234 * 1235 * @return string 1236 * @since 1.23 1237 */ 1238 public static function cascadingsources( $parser, $title = '' ) { 1239 $titleObject = Title::newFromText( $title ); 1240 if ( !( $titleObject instanceof Title ) ) { 1241 $titleObject = $parser->mTitle; 1242 } 1243 if ( $titleObject->areCascadeProtectionSourcesLoaded() 1244 || $parser->incrementExpensiveFunctionCount() 1245 ) { 1246 $names = array(); 1247 $sources = $titleObject->getCascadeProtectionSources(); 1248 foreach ( $sources[0] as $sourceTitle ) { 1249 $names[] = $sourceTitle->getPrefixedText(); 1250 } 1251 return implode( $names, '|' ); 1252 } 1253 return ''; 1254 } 1255 1256 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |