[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/parser/ -> CoreParserFunctions.php (source)

   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  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1