MediaWiki  REL1_23
CoreParserFunctions.php
Go to the documentation of this file.
00001 <?php
00028 class CoreParserFunctions {
00033     static function register( $parser ) {
00034         global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
00035 
00036         # Syntax for arguments (see self::setFunctionHook):
00037         #  "name for lookup in localized magic words array",
00038         #  function callback,
00039         #  optional SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}}
00040         #    instead of {{#int:...}})
00041         $noHashFunctions = array(
00042             'ns', 'nse', 'urlencode', 'lcfirst', 'ucfirst', 'lc', 'uc',
00043             'localurl', 'localurle', 'fullurl', 'fullurle', 'canonicalurl',
00044             'canonicalurle', 'formatnum', 'grammar', 'gender', 'plural',
00045             'numberofpages', 'numberofusers', 'numberofactiveusers',
00046             'numberofarticles', 'numberoffiles', 'numberofadmins',
00047             'numberingroup', 'numberofedits', 'numberofviews', 'language',
00048             'padleft', 'padright', 'anchorencode', 'defaultsort', 'filepath',
00049             'pagesincategory', 'pagesize', 'protectionlevel',
00050             'namespacee', 'namespacenumber', 'talkspace', 'talkspacee',
00051             'subjectspace', 'subjectspacee', 'pagename', 'pagenamee',
00052             'fullpagename', 'fullpagenamee', 'rootpagename', 'rootpagenamee',
00053             'basepagename', 'basepagenamee', 'subpagename', 'subpagenamee',
00054             'talkpagename', 'talkpagenamee', 'subjectpagename',
00055             'subjectpagenamee', 'pageid', 'revisionid', 'revisionday',
00056             'revisionday2', 'revisionmonth', 'revisionmonth1', 'revisionyear',
00057             'revisiontimestamp', 'revisionuser', 'cascadingsources',
00058         );
00059         foreach ( $noHashFunctions as $func ) {
00060             $parser->setFunctionHook( $func, array( __CLASS__, $func ), SFH_NO_HASH );
00061         }
00062 
00063         $parser->setFunctionHook( 'namespace', array( __CLASS__, 'mwnamespace' ), SFH_NO_HASH );
00064         $parser->setFunctionHook( 'int', array( __CLASS__, 'intFunction' ), SFH_NO_HASH );
00065         $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) );
00066         $parser->setFunctionHook( 'speciale', array( __CLASS__, 'speciale' ) );
00067         $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS );
00068         $parser->setFunctionHook( 'formatdate', array( __CLASS__, 'formatDate' ) );
00069 
00070         if ( $wgAllowDisplayTitle ) {
00071             $parser->setFunctionHook( 'displaytitle', array( __CLASS__, 'displaytitle' ), SFH_NO_HASH );
00072         }
00073         if ( $wgAllowSlowParserFunctions ) {
00074             $parser->setFunctionHook( 'pagesinnamespace', array( __CLASS__, 'pagesinnamespace' ), SFH_NO_HASH );
00075         }
00076     }
00077 
00083     static function intFunction( $parser, $part1 = '' /*, ... */ ) {
00084         if ( strval( $part1 ) !== '' ) {
00085             $args = array_slice( func_get_args(), 2 );
00086             $message = wfMessage( $part1, $args )->inLanguage( $parser->getOptions()->getUserLangObj() )->plain();
00087             return array( $message, 'noparse' => false );
00088         } else {
00089             return array( 'found' => false );
00090         }
00091     }
00092 
00100     static function formatDate( $parser, $date, $defaultPref = null ) {
00101         $lang = $parser->getFunctionLang();
00102         $df = DateFormatter::getInstance( $lang );
00103 
00104         $date = trim( $date );
00105 
00106         $pref = $parser->getOptions()->getDateFormat();
00107 
00108         // Specify a different default date format other than the the normal default
00109         // if the user has 'default' for their setting
00110         if ( $pref == 'default' && $defaultPref ) {
00111             $pref = $defaultPref;
00112         }
00113 
00114         $date = $df->reformat( $pref, $date, array( 'match-whole' ) );
00115         return $date;
00116     }
00117 
00118     static function ns( $parser, $part1 = '' ) {
00119         global $wgContLang;
00120         if ( intval( $part1 ) || $part1 == "0" ) {
00121             $index = intval( $part1 );
00122         } else {
00123             $index = $wgContLang->getNsIndex( str_replace( ' ', '_', $part1 ) );
00124         }
00125         if ( $index !== false ) {
00126             return $wgContLang->getFormattedNsText( $index );
00127         } else {
00128             return array( 'found' => false );
00129         }
00130     }
00131 
00132     static function nse( $parser, $part1 = '' ) {
00133         $ret = self::ns( $parser, $part1 );
00134         if ( is_string( $ret ) ) {
00135             $ret = wfUrlencode( str_replace( ' ', '_', $ret ) );
00136         }
00137         return $ret;
00138     }
00139 
00152     static function urlencode( $parser, $s = '', $arg = null ) {
00153         static $magicWords = null;
00154         if ( is_null( $magicWords ) ) {
00155             $magicWords = new MagicWordArray( array( 'url_path', 'url_query', 'url_wiki' ) );
00156         }
00157         switch ( $magicWords->matchStartToEnd( $arg ) ) {
00158 
00159             // Encode as though it's a wiki page, '_' for ' '.
00160             case 'url_wiki':
00161                 $func = 'wfUrlencode';
00162                 $s = str_replace( ' ', '_', $s );
00163                 break;
00164 
00165             // Encode for an HTTP Path, '%20' for ' '.
00166             case 'url_path':
00167                 $func = 'rawurlencode';
00168                 break;
00169 
00170             // Encode for HTTP query, '+' for ' '.
00171             case 'url_query':
00172             default:
00173                 $func = 'urlencode';
00174         }
00175         return $parser->markerSkipCallback( $s, $func );
00176     }
00177 
00178     static function lcfirst( $parser, $s = '' ) {
00179         global $wgContLang;
00180         return $wgContLang->lcfirst( $s );
00181     }
00182 
00183     static function ucfirst( $parser, $s = '' ) {
00184         global $wgContLang;
00185         return $wgContLang->ucfirst( $s );
00186     }
00187 
00193     static function lc( $parser, $s = '' ) {
00194         global $wgContLang;
00195         return $parser->markerSkipCallback( $s, array( $wgContLang, 'lc' ) );
00196     }
00197 
00203     static function uc( $parser, $s = '' ) {
00204         global $wgContLang;
00205         return $parser->markerSkipCallback( $s, array( $wgContLang, 'uc' ) );
00206     }
00207 
00208     static function localurl( $parser, $s = '', $arg = null ) {
00209         return self::urlFunction( 'getLocalURL', $s, $arg );
00210     }
00211 
00212     static function localurle( $parser, $s = '', $arg = null ) {
00213         $temp = self::urlFunction( 'getLocalURL', $s, $arg );
00214         if ( !is_string( $temp ) ) {
00215             return $temp;
00216         } else {
00217             return htmlspecialchars( $temp );
00218         }
00219     }
00220 
00221     static function fullurl( $parser, $s = '', $arg = null ) {
00222         return self::urlFunction( 'getFullURL', $s, $arg );
00223     }
00224 
00225     static function fullurle( $parser, $s = '', $arg = null ) {
00226         $temp = self::urlFunction( 'getFullURL', $s, $arg );
00227         if ( !is_string( $temp ) ) {
00228             return $temp;
00229         } else {
00230             return htmlspecialchars( $temp );
00231         }
00232     }
00233 
00234     static function canonicalurl( $parser, $s = '', $arg = null ) {
00235         return self::urlFunction( 'getCanonicalURL', $s, $arg );
00236     }
00237 
00238     static function canonicalurle( $parser, $s = '', $arg = null ) {
00239         return self::urlFunction( 'escapeCanonicalURL', $s, $arg );
00240     }
00241 
00242     static function urlFunction( $func, $s = '', $arg = null ) {
00243         $title = Title::newFromText( $s );
00244         # Due to order of execution of a lot of bits, the values might be encoded
00245         # before arriving here; if that's true, then the title can't be created
00246         # and the variable will fail. If we can't get a decent title from the first
00247         # attempt, url-decode and try for a second.
00248         if ( is_null( $title ) ) {
00249             $title = Title::newFromURL( urldecode( $s ) );
00250         }
00251         if ( !is_null( $title ) ) {
00252             # Convert NS_MEDIA -> NS_FILE
00253             if ( $title->getNamespace() == NS_MEDIA ) {
00254                 $title = Title::makeTitle( NS_FILE, $title->getDBkey() );
00255             }
00256             if ( !is_null( $arg ) ) {
00257                 $text = $title->$func( $arg );
00258             } else {
00259                 $text = $title->$func();
00260             }
00261             return $text;
00262         } else {
00263             return array( 'found' => false );
00264         }
00265     }
00266 
00273     static function formatnum( $parser, $num = '', $arg = null ) {
00274         if ( self::matchAgainstMagicword( 'rawsuffix', $arg ) ) {
00275             $func = array( $parser->getFunctionLang(), 'parseFormattedNumber' );
00276         } elseif ( self::matchAgainstMagicword( 'nocommafysuffix', $arg ) ) {
00277             $func = array( $parser->getFunctionLang(), 'formatNumNoSeparators' );
00278         } else {
00279             $func = array( $parser->getFunctionLang(), 'formatNum' );
00280         }
00281         return $parser->markerSkipCallback( $num, $func );
00282     }
00283 
00290     static function grammar( $parser, $case = '', $word = '' ) {
00291         $word = $parser->killMarkers( $word );
00292         return $parser->getFunctionLang()->convertGrammar( $word, $case );
00293     }
00294 
00300     static function gender( $parser, $username ) {
00301         wfProfileIn( __METHOD__ );
00302         $forms = array_slice( func_get_args(), 2 );
00303 
00304         // Some shortcuts to avoid loading user data unnecessarily
00305         if ( count( $forms ) === 0 ) {
00306             wfProfileOut( __METHOD__ );
00307             return '';
00308         } elseif ( count( $forms ) === 1 ) {
00309             wfProfileOut( __METHOD__ );
00310             return $forms[0];
00311         }
00312 
00313         $username = trim( $username );
00314 
00315         // default
00316         $gender = User::getDefaultOption( 'gender' );
00317 
00318         // allow prefix.
00319         $title = Title::newFromText( $username );
00320 
00321         if ( $title && $title->getNamespace() == NS_USER ) {
00322             $username = $title->getText();
00323         }
00324 
00325         // check parameter, or use the ParserOptions if in interface message
00326         $user = User::newFromName( $username );
00327         if ( $user ) {
00328             $gender = GenderCache::singleton()->getGenderOf( $user, __METHOD__ );
00329         } elseif ( $username === '' && $parser->getOptions()->getInterfaceMessage() ) {
00330             $gender = GenderCache::singleton()->getGenderOf( $parser->getOptions()->getUser(), __METHOD__ );
00331         }
00332         $ret = $parser->getFunctionLang()->gender( $gender, $forms );
00333         wfProfileOut( __METHOD__ );
00334         return $ret;
00335     }
00336 
00342     static function plural( $parser, $text = '' ) {
00343         $forms = array_slice( func_get_args(), 2 );
00344         $text = $parser->getFunctionLang()->parseFormattedNumber( $text );
00345         settype( $text, ctype_digit( $text ) ? 'int' : 'float' );
00346         return $parser->getFunctionLang()->convertPlural( $text, $forms );
00347     }
00348 
00357     static function displaytitle( $parser, $text = '' ) {
00358         global $wgRestrictDisplayTitle;
00359 
00360         // parse a limited subset of wiki markup (just the single quote items)
00361         $text = $parser->doQuotes( $text );
00362 
00363         // remove stripped text (e.g. the UNIQ-QINU stuff) that was generated by tag extensions/whatever
00364         $text = preg_replace( '/' . preg_quote( $parser->uniqPrefix(), '/' ) . '.*?'
00365             . preg_quote( Parser::MARKER_SUFFIX, '/' ) . '/', '', $text );
00366 
00367         // list of disallowed tags for DISPLAYTITLE
00368         // these will be escaped even though they are allowed in normal wiki text
00369         $bad = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr',
00370             'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rp', 'br' );
00371 
00372         // disallow some styles that could be used to bypass $wgRestrictDisplayTitle
00373         if ( $wgRestrictDisplayTitle ) {
00374             $htmlTagsCallback = function ( &$params ) {
00375                 $decoded = Sanitizer::decodeTagAttributes( $params );
00376 
00377                 if ( isset( $decoded['style'] ) ) {
00378                     // this is called later anyway, but we need it right now for the regexes below to be safe
00379                     // calling it twice doesn't hurt
00380                     $decoded['style'] = Sanitizer::checkCss( $decoded['style'] );
00381 
00382                     if ( preg_match( '/(display|user-select|visibility)\s*:/i', $decoded['style'] ) ) {
00383                         $decoded['style'] = '/* attempt to bypass $wgRestrictDisplayTitle */';
00384                     }
00385                 }
00386 
00387                 $params = Sanitizer::safeEncodeTagAttributes( $decoded );
00388             };
00389         } else {
00390             $htmlTagsCallback = null;
00391         }
00392 
00393         // only requested titles that normalize to the actual title are allowed through
00394         // if $wgRestrictDisplayTitle is true (it is by default)
00395         // mimic the escaping process that occurs in OutputPage::setPageTitle
00396         $text = Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags( $text, $htmlTagsCallback, array(), array(), $bad ) );
00397         $title = Title::newFromText( Sanitizer::stripAllTags( $text ) );
00398 
00399         if ( !$wgRestrictDisplayTitle ) {
00400             $parser->mOutput->setDisplayTitle( $text );
00401         } elseif ( $title instanceof Title && !$title->hasFragment() && $title->equals( $parser->mTitle ) ) {
00402             $parser->mOutput->setDisplayTitle( $text );
00403         }
00404 
00405         return '';
00406     }
00407 
00415     private static function matchAgainstMagicword( $magicword, $value ) {
00416         $value = trim( strval( $value ) );
00417         if ( $value === '' ) {
00418             return false;
00419         }
00420         $mwObject = MagicWord::get( $magicword );
00421         return $mwObject->matchStartToEnd( $value );
00422     }
00423 
00424     static function formatRaw( $num, $raw ) {
00425         if ( self::matchAgainstMagicword( 'rawsuffix', $raw ) ) {
00426             return $num;
00427         } else {
00428             global $wgContLang;
00429             return $wgContLang->formatNum( $num );
00430         }
00431     }
00432     static function numberofpages( $parser, $raw = null ) {
00433         return self::formatRaw( SiteStats::pages(), $raw );
00434     }
00435     static function numberofusers( $parser, $raw = null ) {
00436         return self::formatRaw( SiteStats::users(), $raw );
00437     }
00438     static function numberofactiveusers( $parser, $raw = null ) {
00439         return self::formatRaw( SiteStats::activeUsers(), $raw );
00440     }
00441     static function numberofarticles( $parser, $raw = null ) {
00442         return self::formatRaw( SiteStats::articles(), $raw );
00443     }
00444     static function numberoffiles( $parser, $raw = null ) {
00445         return self::formatRaw( SiteStats::images(), $raw );
00446     }
00447     static function numberofadmins( $parser, $raw = null ) {
00448         return self::formatRaw( SiteStats::numberingroup( 'sysop' ), $raw );
00449     }
00450     static function numberofedits( $parser, $raw = null ) {
00451         return self::formatRaw( SiteStats::edits(), $raw );
00452     }
00453     static function numberofviews( $parser, $raw = null ) {
00454         global $wgDisableCounters;
00455         return !$wgDisableCounters ? self::formatRaw( SiteStats::views(), $raw ) : '';
00456     }
00457     static function pagesinnamespace( $parser, $namespace = 0, $raw = null ) {
00458         return self::formatRaw( SiteStats::pagesInNs( intval( $namespace ) ), $raw );
00459     }
00460     static function numberingroup( $parser, $name = '', $raw = null ) {
00461         return self::formatRaw( SiteStats::numberingroup( strtolower( $name ) ), $raw );
00462     }
00463 
00471     static function mwnamespace( $parser, $title = null ) {
00472         $t = Title::newFromText( $title );
00473         if ( is_null( $t ) ) {
00474             return '';
00475         }
00476         return str_replace( '_', ' ', $t->getNsText() );
00477     }
00478     static function namespacee( $parser, $title = null ) {
00479         $t = Title::newFromText( $title );
00480         if ( is_null( $t ) ) {
00481             return '';
00482         }
00483         return wfUrlencode( $t->getNsText() );
00484     }
00485     static function namespacenumber( $parser, $title = null ) {
00486         $t = Title::newFromText( $title );
00487         if ( is_null( $t ) ) {
00488             return '';
00489         }
00490         return $t->getNamespace();
00491     }
00492     static function talkspace( $parser, $title = null ) {
00493         $t = Title::newFromText( $title );
00494         if ( is_null( $t ) || !$t->canTalk() ) {
00495             return '';
00496         }
00497         return str_replace( '_', ' ', $t->getTalkNsText() );
00498     }
00499     static function talkspacee( $parser, $title = null ) {
00500         $t = Title::newFromText( $title );
00501         if ( is_null( $t ) || !$t->canTalk() ) {
00502             return '';
00503         }
00504         return wfUrlencode( $t->getTalkNsText() );
00505     }
00506     static function subjectspace( $parser, $title = null ) {
00507         $t = Title::newFromText( $title );
00508         if ( is_null( $t ) ) {
00509             return '';
00510         }
00511         return str_replace( '_', ' ', $t->getSubjectNsText() );
00512     }
00513     static function subjectspacee( $parser, $title = null ) {
00514         $t = Title::newFromText( $title );
00515         if ( is_null( $t ) ) {
00516             return '';
00517         }
00518         return wfUrlencode( $t->getSubjectNsText() );
00519     }
00520 
00526     static function pagename( $parser, $title = null ) {
00527         $t = Title::newFromText( $title );
00528         if ( is_null( $t ) ) {
00529             return '';
00530         }
00531         return wfEscapeWikiText( $t->getText() );
00532     }
00533     static function pagenamee( $parser, $title = null ) {
00534         $t = Title::newFromText( $title );
00535         if ( is_null( $t ) ) {
00536             return '';
00537         }
00538         return wfEscapeWikiText( $t->getPartialURL() );
00539     }
00540     static function fullpagename( $parser, $title = null ) {
00541         $t = Title::newFromText( $title );
00542         if ( is_null( $t ) || !$t->canTalk() ) {
00543             return '';
00544         }
00545         return wfEscapeWikiText( $t->getPrefixedText() );
00546     }
00547     static function fullpagenamee( $parser, $title = null ) {
00548         $t = Title::newFromText( $title );
00549         if ( is_null( $t ) || !$t->canTalk() ) {
00550             return '';
00551         }
00552         return wfEscapeWikiText( $t->getPrefixedURL() );
00553     }
00554     static function subpagename( $parser, $title = null ) {
00555         $t = Title::newFromText( $title );
00556         if ( is_null( $t ) ) {
00557             return '';
00558         }
00559         return wfEscapeWikiText( $t->getSubpageText() );
00560     }
00561     static function subpagenamee( $parser, $title = null ) {
00562         $t = Title::newFromText( $title );
00563         if ( is_null( $t ) ) {
00564             return '';
00565         }
00566         return wfEscapeWikiText( $t->getSubpageUrlForm() );
00567     }
00568     static function rootpagename( $parser, $title = null ) {
00569         $t = Title::newFromText( $title );
00570         if ( is_null( $t ) ) {
00571             return '';
00572         }
00573         return wfEscapeWikiText( $t->getRootText() );
00574     }
00575     static function rootpagenamee( $parser, $title = null ) {
00576         $t = Title::newFromText( $title );
00577         if ( is_null( $t ) ) {
00578             return '';
00579         }
00580         return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getRootText() ) ) );
00581     }
00582     static function basepagename( $parser, $title = null ) {
00583         $t = Title::newFromText( $title );
00584         if ( is_null( $t ) ) {
00585             return '';
00586         }
00587         return wfEscapeWikiText( $t->getBaseText() );
00588     }
00589     static function basepagenamee( $parser, $title = null ) {
00590         $t = Title::newFromText( $title );
00591         if ( is_null( $t ) ) {
00592             return '';
00593         }
00594         return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getBaseText() ) ) );
00595     }
00596     static function talkpagename( $parser, $title = null ) {
00597         $t = Title::newFromText( $title );
00598         if ( is_null( $t ) || !$t->canTalk() ) {
00599             return '';
00600         }
00601         return wfEscapeWikiText( $t->getTalkPage()->getPrefixedText() );
00602     }
00603     static function talkpagenamee( $parser, $title = null ) {
00604         $t = Title::newFromText( $title );
00605         if ( is_null( $t ) || !$t->canTalk() ) {
00606             return '';
00607         }
00608         return wfEscapeWikiText( $t->getTalkPage()->getPrefixedURL() );
00609     }
00610     static function subjectpagename( $parser, $title = null ) {
00611         $t = Title::newFromText( $title );
00612         if ( is_null( $t ) ) {
00613             return '';
00614         }
00615         return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedText() );
00616     }
00617     static function subjectpagenamee( $parser, $title = null ) {
00618         $t = Title::newFromText( $title );
00619         if ( is_null( $t ) ) {
00620             return '';
00621         }
00622         return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedURL() );
00623     }
00624 
00631     static function pagesincategory( $parser, $name = '', $arg1 = null, $arg2 = null ) {
00632         global $wgContLang;
00633         static $magicWords = null;
00634         if ( is_null( $magicWords ) ) {
00635             $magicWords = new MagicWordArray( array(
00636                 'pagesincategory_all',
00637                 'pagesincategory_pages',
00638                 'pagesincategory_subcats',
00639                 'pagesincategory_files'
00640             ) );
00641         }
00642         static $cache = array();
00643 
00644         // split the given option to its variable
00645         if ( self::matchAgainstMagicword( 'rawsuffix', $arg1 ) ) {
00646             //{{pagesincategory:|raw[|type]}}
00647             $raw = $arg1;
00648             $type = $magicWords->matchStartToEnd( $arg2 );
00649         } else {
00650             //{{pagesincategory:[|type[|raw]]}}
00651             $type = $magicWords->matchStartToEnd( $arg1 );
00652             $raw = $arg2;
00653         }
00654         if ( !$type ) { //backward compatibility
00655             $type = 'pagesincategory_all';
00656         }
00657 
00658         $title = Title::makeTitleSafe( NS_CATEGORY, $name );
00659         if ( !$title ) { # invalid title
00660             return self::formatRaw( 0, $raw );
00661         }
00662         $wgContLang->findVariantLink( $name, $title, true );
00663 
00664         // Normalize name for cache
00665         $name = $title->getDBkey();
00666 
00667         if ( !isset( $cache[$name] ) ) {
00668             $category = Category::newFromTitle( $title );
00669 
00670             $allCount = $subcatCount = $fileCount = $pagesCount = 0;
00671             if ( $parser->incrementExpensiveFunctionCount() ) {
00672                 // $allCount is the total number of cat members,
00673                 // not the count of how many members are normal pages.
00674                 $allCount = (int)$category->getPageCount();
00675                 $subcatCount = (int)$category->getSubcatCount();
00676                 $fileCount = (int)$category->getFileCount();
00677                 $pagesCount = $allCount - $subcatCount - $fileCount;
00678             }
00679             $cache[$name]['pagesincategory_all'] = $allCount;
00680             $cache[$name]['pagesincategory_pages'] = $pagesCount;
00681             $cache[$name]['pagesincategory_subcats'] = $subcatCount;
00682             $cache[$name]['pagesincategory_files'] = $fileCount;
00683         }
00684 
00685         $count = $cache[$name][$type];
00686         return self::formatRaw( $count, $raw );
00687     }
00688 
00698     static function pagesize( $parser, $page = '', $raw = null ) {
00699         $title = Title::newFromText( $page );
00700 
00701         if ( !is_object( $title ) ) {
00702             return self::formatRaw( 0, $raw );
00703         }
00704 
00705         // fetch revision from cache/database and return the value
00706         $rev = self::getCachedRevisionObject( $parser, $title );
00707         $length = $rev ? $rev->getSize() : 0;
00708         return self::formatRaw( $length, $raw );
00709     }
00710 
00723     static function protectionlevel( $parser, $type = '', $title = '' ) {
00724         $titleObject = Title::newFromText( $title );
00725         if ( !( $titleObject instanceof Title ) ) {
00726             $titleObject = $parser->mTitle;
00727         }
00728         if ( $titleObject->areRestrictionsLoaded() || $parser->incrementExpensiveFunctionCount() ) {
00729             $restrictions = $titleObject->getRestrictions( strtolower( $type ) );
00730             # Title::getRestrictions returns an array, its possible it may have
00731             # multiple values in the future
00732             return implode( $restrictions, ',' );
00733         }
00734         return '';
00735     }
00736 
00744     static function language( $parser, $code = '', $inLanguage = '' ) {
00745         $code = strtolower( $code );
00746         $inLanguage = strtolower( $inLanguage );
00747         $lang = Language::fetchLanguageName( $code, $inLanguage );
00748         return $lang !== '' ? $lang : wfBCP47( $code );
00749     }
00750 
00755     static function pad( $parser, $string, $length, $padding = '0', $direction = STR_PAD_RIGHT ) {
00756         $padding = $parser->killMarkers( $padding );
00757         $lengthOfPadding = mb_strlen( $padding );
00758         if ( $lengthOfPadding == 0 ) {
00759             return $string;
00760         }
00761 
00762         # The remaining length to add counts down to 0 as padding is added
00763         $length = min( $length, 500 ) - mb_strlen( $string );
00764         # $finalPadding is just $padding repeated enough times so that
00765         # mb_strlen( $string ) + mb_strlen( $finalPadding ) == $length
00766         $finalPadding = '';
00767         while ( $length > 0 ) {
00768             # If $length < $lengthofPadding, truncate $padding so we get the
00769             # exact length desired.
00770             $finalPadding .= mb_substr( $padding, 0, $length );
00771             $length -= $lengthOfPadding;
00772         }
00773 
00774         if ( $direction == STR_PAD_LEFT ) {
00775             return $finalPadding . $string;
00776         } else {
00777             return $string . $finalPadding;
00778         }
00779     }
00780 
00781     static function padleft( $parser, $string = '', $length = 0, $padding = '0' ) {
00782         return self::pad( $parser, $string, $length, $padding, STR_PAD_LEFT );
00783     }
00784 
00785     static function padright( $parser, $string = '', $length = 0, $padding = '0' ) {
00786         return self::pad( $parser, $string, $length, $padding );
00787     }
00788 
00794     static function anchorencode( $parser, $text ) {
00795         $text = $parser->killMarkers( $text );
00796         return (string)substr( $parser->guessSectionNameFromWikiText( $text ), 1 );
00797     }
00798 
00799     static function special( $parser, $text ) {
00800         list( $page, $subpage ) = SpecialPageFactory::resolveAlias( $text );
00801         if ( $page ) {
00802             $title = SpecialPage::getTitleFor( $page, $subpage );
00803             return $title->getPrefixedText();
00804         } else {
00805             // unknown special page, just use the given text as its title, if at all possible
00806             $title = Title::makeTitleSafe( NS_SPECIAL, $text );
00807             return $title ? $title->getPrefixedText() : self::special( $parser, 'Badtitle' );
00808         }
00809     }
00810 
00811     static function speciale( $parser, $text ) {
00812         return wfUrlencode( str_replace( ' ', '_', self::special( $parser, $text ) ) );
00813     }
00814 
00823     public static function defaultsort( $parser, $text, $uarg = '' ) {
00824         static $magicWords = null;
00825         if ( is_null( $magicWords ) ) {
00826             $magicWords = new MagicWordArray( array( 'defaultsort_noerror', 'defaultsort_noreplace' ) );
00827         }
00828         $arg = $magicWords->matchStartToEnd( $uarg );
00829 
00830         $text = trim( $text );
00831         if ( strlen( $text ) == 0 ) {
00832             return '';
00833         }
00834         $old = $parser->getCustomDefaultSort();
00835         if ( $old === false || $arg !== 'defaultsort_noreplace' ) {
00836             $parser->setDefaultSort( $text );
00837         }
00838 
00839         if ( $old === false || $old == $text || $arg ) {
00840             return '';
00841         } else {
00842             $converter = $parser->getConverterLanguage()->getConverter();
00843             return '<span class="error">' .
00844                 wfMessage( 'duplicate-defaultsort',
00845                     // Message should be parsed, but these params should only be escaped.
00846                     $converter->markNoConversion( wfEscapeWikiText( $old ) ),
00847                     $converter->markNoConversion( wfEscapeWikiText( $text ) )
00848                 )->inContentLanguage()->text() .
00849                 '</span>';
00850         }
00851     }
00852 
00853     // Usage {{filepath|300}}, {{filepath|nowiki}}, {{filepath|nowiki|300}} or {{filepath|300|nowiki}}
00854     // or {{filepath|300px}}, {{filepath|200x300px}}, {{filepath|nowiki|200x300px}}, {{filepath|200x300px|nowiki}}
00855     public static function filepath( $parser, $name = '', $argA = '', $argB = '' ) {
00856         $file = wfFindFile( $name );
00857 
00858         if ( $argA == 'nowiki' ) {
00859             // {{filepath: | option [| size] }}
00860             $isNowiki = true;
00861             $parsedWidthParam = $parser->parseWidthParam( $argB );
00862         } else {
00863             // {{filepath: [| size [|option]] }}
00864             $parsedWidthParam = $parser->parseWidthParam( $argA );
00865             $isNowiki = ( $argB == 'nowiki' );
00866         }
00867 
00868         if ( $file ) {
00869             $url = $file->getFullUrl();
00870 
00871             // If a size is requested...
00872             if ( count( $parsedWidthParam ) ) {
00873                 $mto = $file->transform( $parsedWidthParam );
00874                 // ... and we can
00875                 if ( $mto && !$mto->isError() ) {
00876                     // ... change the URL to point to a thumbnail.
00877                     $url = wfExpandUrl( $mto->getUrl(), PROTO_RELATIVE );
00878                 }
00879             }
00880             if ( $isNowiki ) {
00881                 return array( $url, 'nowiki' => true );
00882             }
00883             return $url;
00884         } else {
00885             return '';
00886         }
00887     }
00888 
00893     public static function tagObj( $parser, $frame, $args ) {
00894         if ( !count( $args ) ) {
00895             return '';
00896         }
00897         $tagName = strtolower( trim( $frame->expand( array_shift( $args ) ) ) );
00898 
00899         if ( count( $args ) ) {
00900             $inner = $frame->expand( array_shift( $args ) );
00901         } else {
00902             $inner = null;
00903         }
00904 
00905         $stripList = $parser->getStripList();
00906         if ( !in_array( $tagName, $stripList ) ) {
00907             return '<span class="error">' .
00908                 wfMessage( 'unknown_extension_tag', $tagName )->inContentLanguage()->text() .
00909                 '</span>';
00910         }
00911 
00912         $attributes = array();
00913         foreach ( $args as $arg ) {
00914             $bits = $arg->splitArg();
00915             if ( strval( $bits['index'] ) === '' ) {
00916                 $name = trim( $frame->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
00917                 $value = trim( $frame->expand( $bits['value'] ) );
00918                 if ( preg_match( '/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m ) ) {
00919                     $value = isset( $m[1] ) ? $m[1] : '';
00920                 }
00921                 $attributes[$name] = $value;
00922             }
00923         }
00924 
00925         $params = array(
00926             'name' => $tagName,
00927             'inner' => $inner,
00928             'attributes' => $attributes,
00929             'close' => "</$tagName>",
00930         );
00931         return $parser->extensionSubstitution( $params, $frame );
00932     }
00933 
00946     private static function getCachedRevisionObject( $parser, $title = null ) {
00947         static $cache = array();
00948 
00949         if ( is_null( $title ) ) {
00950             return null;
00951         }
00952 
00953         // Use the revision from the parser itself, when param is the current page
00954         // and the revision is the current one
00955         if ( $title->equals( $parser->getTitle() ) ) {
00956             $parserRev = $parser->getRevisionObject();
00957             if ( $parserRev && $parserRev->isCurrent() ) {
00958                 // force reparse after edit with vary-revision flag
00959                 $parser->getOutput()->setFlag( 'vary-revision' );
00960                 wfDebug( __METHOD__ . ": use current revision from parser, setting vary-revision...\n" );
00961                 return $parserRev;
00962             }
00963         }
00964 
00965         // Normalize name for cache
00966         $page = $title->getPrefixedDBkey();
00967 
00968         if ( array_key_exists( $page, $cache ) ) { // cache contains null values
00969             return $cache[$page];
00970         }
00971         if ( $parser->incrementExpensiveFunctionCount() ) {
00972             $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
00973             $pageID = $rev ? $rev->getPage() : 0;
00974             $revID = $rev ? $rev->getId() : 0;
00975             $cache[$page] = $rev; // maybe null
00976 
00977             // Register dependency in templatelinks
00978             $parser->getOutput()->addTemplate( $title, $pageID, $revID );
00979 
00980             return $rev;
00981         }
00982         $cache[$page] = null;
00983         return null;
00984     }
00985 
00992     public static function pageid( $parser, $title = null ) {
00993         $t = Title::newFromText( $title );
00994         if ( is_null( $t ) ) {
00995             return '';
00996         }
00997         // Use title from parser to have correct pageid after edit
00998         if ( $t->equals( $parser->getTitle() ) ) {
00999             $t = $parser->getTitle();
01000             return $t->getArticleID();
01001         }
01002 
01003         // These can't have ids
01004         if ( !$t->canExist() || $t->isExternal() ) {
01005             return 0;
01006         }
01007 
01008         // Check the link cache, maybe something already looked it up.
01009         $linkCache = LinkCache::singleton();
01010         $pdbk = $t->getPrefixedDBkey();
01011         $id = $linkCache->getGoodLinkID( $pdbk );
01012         if ( $id != 0 ) {
01013             $parser->mOutput->addLink( $t, $id );
01014             return $id;
01015         }
01016         if ( $linkCache->isBadLink( $pdbk ) ) {
01017             $parser->mOutput->addLink( $t, 0 );
01018             return $id;
01019         }
01020 
01021         // We need to load it from the DB, so mark expensive
01022         if ( $parser->incrementExpensiveFunctionCount() ) {
01023             $id = $t->getArticleID();
01024             $parser->mOutput->addLink( $t, $id );
01025             return $id;
01026         }
01027         return null;
01028     }
01029 
01036     public static function revisionid( $parser, $title = null ) {
01037         $t = Title::newFromText( $title );
01038         if ( is_null( $t ) ) {
01039             return '';
01040         }
01041         // fetch revision from cache/database and return the value
01042         $rev = self::getCachedRevisionObject( $parser, $t );
01043         return $rev ? $rev->getId() : '';
01044     }
01045 
01052     public static function revisionday( $parser, $title = null ) {
01053         $t = Title::newFromText( $title );
01054         if ( is_null( $t ) ) {
01055             return '';
01056         }
01057         // fetch revision from cache/database and return the value
01058         $rev = self::getCachedRevisionObject( $parser, $t );
01059         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'j' ) : '';
01060     }
01061 
01068     public static function revisionday2( $parser, $title = null ) {
01069         $t = Title::newFromText( $title );
01070         if ( is_null( $t ) ) {
01071             return '';
01072         }
01073         // fetch revision from cache/database and return the value
01074         $rev = self::getCachedRevisionObject( $parser, $t );
01075         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'd' ) : '';
01076     }
01077 
01084     public static function revisionmonth( $parser, $title = null ) {
01085         $t = Title::newFromText( $title );
01086         if ( is_null( $t ) ) {
01087             return '';
01088         }
01089         // fetch revision from cache/database and return the value
01090         $rev = self::getCachedRevisionObject( $parser, $t );
01091         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'm' ) : '';
01092     }
01093 
01100     public static function revisionmonth1( $parser, $title = null ) {
01101         $t = Title::newFromText( $title );
01102         if ( is_null( $t ) ) {
01103             return '';
01104         }
01105         // fetch revision from cache/database and return the value
01106         $rev = self::getCachedRevisionObject( $parser, $t );
01107         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'n' ) : '';
01108     }
01109 
01116     public static function revisionyear( $parser, $title = null ) {
01117         $t = Title::newFromText( $title );
01118         if ( is_null( $t ) ) {
01119             return '';
01120         }
01121         // fetch revision from cache/database and return the value
01122         $rev = self::getCachedRevisionObject( $parser, $t );
01123         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'Y' ) : '';
01124     }
01125 
01132     public static function revisiontimestamp( $parser, $title = null ) {
01133         $t = Title::newFromText( $title );
01134         if ( is_null( $t ) ) {
01135             return '';
01136         }
01137         // fetch revision from cache/database and return the value
01138         $rev = self::getCachedRevisionObject( $parser, $t );
01139         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'YmdHis' ) : '';
01140     }
01141 
01148     public static function revisionuser( $parser, $title = null ) {
01149         $t = Title::newFromText( $title );
01150         if ( is_null( $t ) ) {
01151             return '';
01152         }
01153         // fetch revision from cache/database and return the value
01154         $rev = self::getCachedRevisionObject( $parser, $t );
01155         return $rev ? $rev->getUserText() : '';
01156     }
01157 
01170     public static function cascadingsources( $parser, $title = '' ) {
01171         $titleObject = Title::newFromText( $title );
01172         if ( !( $titleObject instanceof Title ) ) {
01173             $titleObject = $parser->mTitle;
01174         }
01175         if ( $titleObject->areCascadeProtectionSourcesLoaded()
01176             || $parser->incrementExpensiveFunctionCount()
01177         ) {
01178             $names = array();
01179             $sources = $titleObject->getCascadeProtectionSources();
01180             foreach ( $sources[0] as $sourceTitle ) {
01181                 $names[] = $sourceTitle->getPrefixedText();
01182             }
01183             return implode( $names, '|' );
01184         }
01185         return '';
01186     }
01187 
01188 }