MediaWiki  REL1_24
CoreParserFunctions.php
Go to the documentation of this file.
00001 <?php
00028 class CoreParserFunctions {
00033     public static function register( $parser ) {
00034         global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions;
00035 
00036         # Syntax for arguments (see Parser::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(
00075                 'pagesinnamespace',
00076                 array( __CLASS__, 'pagesinnamespace' ),
00077                 SFH_NO_HASH
00078             );
00079         }
00080     }
00081 
00087     public static function intFunction( $parser, $part1 = '' /*, ... */ ) {
00088         if ( strval( $part1 ) !== '' ) {
00089             $args = array_slice( func_get_args(), 2 );
00090             $message = wfMessage( $part1, $args )
00091                 ->inLanguage( $parser->getOptions()->getUserLangObj() )->plain();
00092 
00093             return array( $message, 'noparse' => false );
00094         } else {
00095             return array( 'found' => false );
00096         }
00097     }
00098 
00106     public static function formatDate( $parser, $date, $defaultPref = null ) {
00107         $lang = $parser->getFunctionLang();
00108         $df = DateFormatter::getInstance( $lang );
00109 
00110         $date = trim( $date );
00111 
00112         $pref = $parser->getOptions()->getDateFormat();
00113 
00114         // Specify a different default date format other than the the normal default
00115         // if the user has 'default' for their setting
00116         if ( $pref == 'default' && $defaultPref ) {
00117             $pref = $defaultPref;
00118         }
00119 
00120         $date = $df->reformat( $pref, $date, array( 'match-whole' ) );
00121         return $date;
00122     }
00123 
00124     public static function ns( $parser, $part1 = '' ) {
00125         global $wgContLang;
00126         if ( intval( $part1 ) || $part1 == "0" ) {
00127             $index = intval( $part1 );
00128         } else {
00129             $index = $wgContLang->getNsIndex( str_replace( ' ', '_', $part1 ) );
00130         }
00131         if ( $index !== false ) {
00132             return $wgContLang->getFormattedNsText( $index );
00133         } else {
00134             return array( 'found' => false );
00135         }
00136     }
00137 
00138     public static function nse( $parser, $part1 = '' ) {
00139         $ret = self::ns( $parser, $part1 );
00140         if ( is_string( $ret ) ) {
00141             $ret = wfUrlencode( str_replace( ' ', '_', $ret ) );
00142         }
00143         return $ret;
00144     }
00145 
00158     public static function urlencode( $parser, $s = '', $arg = null ) {
00159         static $magicWords = null;
00160         if ( is_null( $magicWords ) ) {
00161             $magicWords = new MagicWordArray( array( 'url_path', 'url_query', 'url_wiki' ) );
00162         }
00163         switch ( $magicWords->matchStartToEnd( $arg ) ) {
00164 
00165             // Encode as though it's a wiki page, '_' for ' '.
00166             case 'url_wiki':
00167                 $func = 'wfUrlencode';
00168                 $s = str_replace( ' ', '_', $s );
00169                 break;
00170 
00171             // Encode for an HTTP Path, '%20' for ' '.
00172             case 'url_path':
00173                 $func = 'rawurlencode';
00174                 break;
00175 
00176             // Encode for HTTP query, '+' for ' '.
00177             case 'url_query':
00178             default:
00179                 $func = 'urlencode';
00180         }
00181         return $parser->markerSkipCallback( $s, $func );
00182     }
00183 
00184     public static function lcfirst( $parser, $s = '' ) {
00185         global $wgContLang;
00186         return $wgContLang->lcfirst( $s );
00187     }
00188 
00189     public static function ucfirst( $parser, $s = '' ) {
00190         global $wgContLang;
00191         return $wgContLang->ucfirst( $s );
00192     }
00193 
00199     public static function lc( $parser, $s = '' ) {
00200         global $wgContLang;
00201         return $parser->markerSkipCallback( $s, array( $wgContLang, 'lc' ) );
00202     }
00203 
00209     public static function uc( $parser, $s = '' ) {
00210         global $wgContLang;
00211         return $parser->markerSkipCallback( $s, array( $wgContLang, 'uc' ) );
00212     }
00213 
00214     public static function localurl( $parser, $s = '', $arg = null ) {
00215         return self::urlFunction( 'getLocalURL', $s, $arg );
00216     }
00217 
00218     public static function localurle( $parser, $s = '', $arg = null ) {
00219         $temp = self::urlFunction( 'getLocalURL', $s, $arg );
00220         if ( !is_string( $temp ) ) {
00221             return $temp;
00222         } else {
00223             return htmlspecialchars( $temp );
00224         }
00225     }
00226 
00227     public static function fullurl( $parser, $s = '', $arg = null ) {
00228         return self::urlFunction( 'getFullURL', $s, $arg );
00229     }
00230 
00231     public static function fullurle( $parser, $s = '', $arg = null ) {
00232         $temp = self::urlFunction( 'getFullURL', $s, $arg );
00233         if ( !is_string( $temp ) ) {
00234             return $temp;
00235         } else {
00236             return htmlspecialchars( $temp );
00237         }
00238     }
00239 
00240     public static function canonicalurl( $parser, $s = '', $arg = null ) {
00241         return self::urlFunction( 'getCanonicalURL', $s, $arg );
00242     }
00243 
00244     public static function canonicalurle( $parser, $s = '', $arg = null ) {
00245         $temp = self::urlFunction( 'getCanonicalURL', $s, $arg );
00246         if ( !is_string( $temp ) ) {
00247             return $temp;
00248         } else {
00249             return htmlspecialchars( $temp );
00250         }
00251     }
00252 
00253     public static function urlFunction( $func, $s = '', $arg = null ) {
00254         $title = Title::newFromText( $s );
00255         # Due to order of execution of a lot of bits, the values might be encoded
00256         # before arriving here; if that's true, then the title can't be created
00257         # and the variable will fail. If we can't get a decent title from the first
00258         # attempt, url-decode and try for a second.
00259         if ( is_null( $title ) ) {
00260             $title = Title::newFromURL( urldecode( $s ) );
00261         }
00262         if ( !is_null( $title ) ) {
00263             # Convert NS_MEDIA -> NS_FILE
00264             if ( $title->getNamespace() == NS_MEDIA ) {
00265                 $title = Title::makeTitle( NS_FILE, $title->getDBkey() );
00266             }
00267             if ( !is_null( $arg ) ) {
00268                 $text = $title->$func( $arg );
00269             } else {
00270                 $text = $title->$func();
00271             }
00272             return $text;
00273         } else {
00274             return array( 'found' => false );
00275         }
00276     }
00277 
00284     public static function formatnum( $parser, $num = '', $arg = null ) {
00285         if ( self::matchAgainstMagicword( 'rawsuffix', $arg ) ) {
00286             $func = array( $parser->getFunctionLang(), 'parseFormattedNumber' );
00287         } elseif ( self::matchAgainstMagicword( 'nocommafysuffix', $arg ) ) {
00288             $func = array( $parser->getFunctionLang(), 'formatNumNoSeparators' );
00289         } else {
00290             $func = array( $parser->getFunctionLang(), 'formatNum' );
00291         }
00292         return $parser->markerSkipCallback( $num, $func );
00293     }
00294 
00301     public static function grammar( $parser, $case = '', $word = '' ) {
00302         $word = $parser->killMarkers( $word );
00303         return $parser->getFunctionLang()->convertGrammar( $word, $case );
00304     }
00305 
00311     public static function gender( $parser, $username ) {
00312         wfProfileIn( __METHOD__ );
00313         $forms = array_slice( func_get_args(), 2 );
00314 
00315         // Some shortcuts to avoid loading user data unnecessarily
00316         if ( count( $forms ) === 0 ) {
00317             wfProfileOut( __METHOD__ );
00318             return '';
00319         } elseif ( count( $forms ) === 1 ) {
00320             wfProfileOut( __METHOD__ );
00321             return $forms[0];
00322         }
00323 
00324         $username = trim( $username );
00325 
00326         // default
00327         $gender = User::getDefaultOption( 'gender' );
00328 
00329         // allow prefix.
00330         $title = Title::newFromText( $username );
00331 
00332         if ( $title && $title->getNamespace() == NS_USER ) {
00333             $username = $title->getText();
00334         }
00335 
00336         // check parameter, or use the ParserOptions if in interface message
00337         $user = User::newFromName( $username );
00338         if ( $user ) {
00339             $gender = GenderCache::singleton()->getGenderOf( $user, __METHOD__ );
00340         } elseif ( $username === '' && $parser->getOptions()->getInterfaceMessage() ) {
00341             $gender = GenderCache::singleton()->getGenderOf( $parser->getOptions()->getUser(), __METHOD__ );
00342         }
00343         $ret = $parser->getFunctionLang()->gender( $gender, $forms );
00344         wfProfileOut( __METHOD__ );
00345         return $ret;
00346     }
00347 
00353     public static function plural( $parser, $text = '' ) {
00354         $forms = array_slice( func_get_args(), 2 );
00355         $text = $parser->getFunctionLang()->parseFormattedNumber( $text );
00356         settype( $text, ctype_digit( $text ) ? 'int' : 'float' );
00357         return $parser->getFunctionLang()->convertPlural( $text, $forms );
00358     }
00359 
00369     public static function displaytitle( $parser, $text = '', $uarg = '' ) {
00370         global $wgRestrictDisplayTitle;
00371 
00372         static $magicWords = null;
00373         if ( is_null( $magicWords ) ) {
00374             $magicWords = new MagicWordArray( array( 'displaytitle_noerror', 'displaytitle_noreplace' ) );
00375         }
00376         $arg = $magicWords->matchStartToEnd( $uarg );
00377 
00378         // parse a limited subset of wiki markup (just the single quote items)
00379         $text = $parser->doQuotes( $text );
00380 
00381         // remove stripped text (e.g. the UNIQ-QINU stuff) that was generated by tag extensions/whatever
00382         $text = preg_replace( '/' . preg_quote( $parser->uniqPrefix(), '/' ) . '.*?'
00383             . preg_quote( Parser::MARKER_SUFFIX, '/' ) . '/', '', $text );
00384 
00385         // list of disallowed tags for DISPLAYTITLE
00386         // these will be escaped even though they are allowed in normal wiki text
00387         $bad = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr',
00388             'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rtc', 'rp', 'br' );
00389 
00390         // disallow some styles that could be used to bypass $wgRestrictDisplayTitle
00391         if ( $wgRestrictDisplayTitle ) {
00392             $htmlTagsCallback = function ( &$params ) {
00393                 $decoded = Sanitizer::decodeTagAttributes( $params );
00394 
00395                 if ( isset( $decoded['style'] ) ) {
00396                     // this is called later anyway, but we need it right now for the regexes below to be safe
00397                     // calling it twice doesn't hurt
00398                     $decoded['style'] = Sanitizer::checkCss( $decoded['style'] );
00399 
00400                     if ( preg_match( '/(display|user-select|visibility)\s*:/i', $decoded['style'] ) ) {
00401                         $decoded['style'] = '/* attempt to bypass $wgRestrictDisplayTitle */';
00402                     }
00403                 }
00404 
00405                 $params = Sanitizer::safeEncodeTagAttributes( $decoded );
00406             };
00407         } else {
00408             $htmlTagsCallback = null;
00409         }
00410 
00411         // only requested titles that normalize to the actual title are allowed through
00412         // if $wgRestrictDisplayTitle is true (it is by default)
00413         // mimic the escaping process that occurs in OutputPage::setPageTitle
00414         $text = Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags(
00415             $text,
00416             $htmlTagsCallback,
00417             array(),
00418             array(),
00419             $bad
00420         ) );
00421         $title = Title::newFromText( Sanitizer::stripAllTags( $text ) );
00422 
00423         if ( !$wgRestrictDisplayTitle ||
00424             ( $title instanceof Title
00425             && !$title->hasFragment()
00426             && $title->equals( $parser->mTitle ) )
00427         ) {
00428             $old = $parser->mOutput->getProperty( 'displaytitle' );
00429             if ( $old === false || $arg !== 'displaytitle_noreplace' ) {
00430                 $parser->mOutput->setDisplayTitle( $text );
00431             }
00432             if ( $old !== false && $old !== $text && !$arg ) {
00433                 $converter = $parser->getConverterLanguage()->getConverter();
00434                 return '<span class="error">' .
00435                     wfMessage( 'duplicate-displaytitle',
00436                         // Message should be parsed, but these params should only be escaped.
00437                         $converter->markNoConversion( wfEscapeWikiText( $old ) ),
00438                         $converter->markNoConversion( wfEscapeWikiText( $text ) )
00439                     )->inContentLanguage()->text() .
00440                     '</span>';
00441             }
00442         }
00443 
00444         return '';
00445     }
00446 
00454     private static function matchAgainstMagicword( $magicword, $value ) {
00455         $value = trim( strval( $value ) );
00456         if ( $value === '' ) {
00457             return false;
00458         }
00459         $mwObject = MagicWord::get( $magicword );
00460         return $mwObject->matchStartToEnd( $value );
00461     }
00462 
00463     public static function formatRaw( $num, $raw ) {
00464         if ( self::matchAgainstMagicword( 'rawsuffix', $raw ) ) {
00465             return $num;
00466         } else {
00467             global $wgContLang;
00468             return $wgContLang->formatNum( $num );
00469         }
00470     }
00471     public static function numberofpages( $parser, $raw = null ) {
00472         return self::formatRaw( SiteStats::pages(), $raw );
00473     }
00474     public static function numberofusers( $parser, $raw = null ) {
00475         return self::formatRaw( SiteStats::users(), $raw );
00476     }
00477     public static function numberofactiveusers( $parser, $raw = null ) {
00478         return self::formatRaw( SiteStats::activeUsers(), $raw );
00479     }
00480     public static function numberofarticles( $parser, $raw = null ) {
00481         return self::formatRaw( SiteStats::articles(), $raw );
00482     }
00483     public static function numberoffiles( $parser, $raw = null ) {
00484         return self::formatRaw( SiteStats::images(), $raw );
00485     }
00486     public static function numberofadmins( $parser, $raw = null ) {
00487         return self::formatRaw( SiteStats::numberingroup( 'sysop' ), $raw );
00488     }
00489     public static function numberofedits( $parser, $raw = null ) {
00490         return self::formatRaw( SiteStats::edits(), $raw );
00491     }
00492     public static function numberofviews( $parser, $raw = null ) {
00493         global $wgDisableCounters;
00494         return !$wgDisableCounters ? self::formatRaw( SiteStats::views(), $raw ) : '';
00495     }
00496     public static function pagesinnamespace( $parser, $namespace = 0, $raw = null ) {
00497         return self::formatRaw( SiteStats::pagesInNs( intval( $namespace ) ), $raw );
00498     }
00499     public static function numberingroup( $parser, $name = '', $raw = null ) {
00500         return self::formatRaw( SiteStats::numberingroup( strtolower( $name ) ), $raw );
00501     }
00502 
00512     public static function mwnamespace( $parser, $title = null ) {
00513         $t = Title::newFromText( $title );
00514         if ( is_null( $t ) ) {
00515             return '';
00516         }
00517         return str_replace( '_', ' ', $t->getNsText() );
00518     }
00519     public static function namespacee( $parser, $title = null ) {
00520         $t = Title::newFromText( $title );
00521         if ( is_null( $t ) ) {
00522             return '';
00523         }
00524         return wfUrlencode( $t->getNsText() );
00525     }
00526     public static function namespacenumber( $parser, $title = null ) {
00527         $t = Title::newFromText( $title );
00528         if ( is_null( $t ) ) {
00529             return '';
00530         }
00531         return $t->getNamespace();
00532     }
00533     public static function talkspace( $parser, $title = null ) {
00534         $t = Title::newFromText( $title );
00535         if ( is_null( $t ) || !$t->canTalk() ) {
00536             return '';
00537         }
00538         return str_replace( '_', ' ', $t->getTalkNsText() );
00539     }
00540     public static function talkspacee( $parser, $title = null ) {
00541         $t = Title::newFromText( $title );
00542         if ( is_null( $t ) || !$t->canTalk() ) {
00543             return '';
00544         }
00545         return wfUrlencode( $t->getTalkNsText() );
00546     }
00547     public static function subjectspace( $parser, $title = null ) {
00548         $t = Title::newFromText( $title );
00549         if ( is_null( $t ) ) {
00550             return '';
00551         }
00552         return str_replace( '_', ' ', $t->getSubjectNsText() );
00553     }
00554     public static function subjectspacee( $parser, $title = null ) {
00555         $t = Title::newFromText( $title );
00556         if ( is_null( $t ) ) {
00557             return '';
00558         }
00559         return wfUrlencode( $t->getSubjectNsText() );
00560     }
00561 
00569     public static function pagename( $parser, $title = null ) {
00570         $t = Title::newFromText( $title );
00571         if ( is_null( $t ) ) {
00572             return '';
00573         }
00574         return wfEscapeWikiText( $t->getText() );
00575     }
00576     public static function pagenamee( $parser, $title = null ) {
00577         $t = Title::newFromText( $title );
00578         if ( is_null( $t ) ) {
00579             return '';
00580         }
00581         return wfEscapeWikiText( $t->getPartialURL() );
00582     }
00583     public static function fullpagename( $parser, $title = null ) {
00584         $t = Title::newFromText( $title );
00585         if ( is_null( $t ) || !$t->canTalk() ) {
00586             return '';
00587         }
00588         return wfEscapeWikiText( $t->getPrefixedText() );
00589     }
00590     public static function fullpagenamee( $parser, $title = null ) {
00591         $t = Title::newFromText( $title );
00592         if ( is_null( $t ) || !$t->canTalk() ) {
00593             return '';
00594         }
00595         return wfEscapeWikiText( $t->getPrefixedURL() );
00596     }
00597     public static function subpagename( $parser, $title = null ) {
00598         $t = Title::newFromText( $title );
00599         if ( is_null( $t ) ) {
00600             return '';
00601         }
00602         return wfEscapeWikiText( $t->getSubpageText() );
00603     }
00604     public static function subpagenamee( $parser, $title = null ) {
00605         $t = Title::newFromText( $title );
00606         if ( is_null( $t ) ) {
00607             return '';
00608         }
00609         return wfEscapeWikiText( $t->getSubpageUrlForm() );
00610     }
00611     public static function rootpagename( $parser, $title = null ) {
00612         $t = Title::newFromText( $title );
00613         if ( is_null( $t ) ) {
00614             return '';
00615         }
00616         return wfEscapeWikiText( $t->getRootText() );
00617     }
00618     public static function rootpagenamee( $parser, $title = null ) {
00619         $t = Title::newFromText( $title );
00620         if ( is_null( $t ) ) {
00621             return '';
00622         }
00623         return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getRootText() ) ) );
00624     }
00625     public static function basepagename( $parser, $title = null ) {
00626         $t = Title::newFromText( $title );
00627         if ( is_null( $t ) ) {
00628             return '';
00629         }
00630         return wfEscapeWikiText( $t->getBaseText() );
00631     }
00632     public static function basepagenamee( $parser, $title = null ) {
00633         $t = Title::newFromText( $title );
00634         if ( is_null( $t ) ) {
00635             return '';
00636         }
00637         return wfEscapeWikiText( wfUrlEncode( str_replace( ' ', '_', $t->getBaseText() ) ) );
00638     }
00639     public static function talkpagename( $parser, $title = null ) {
00640         $t = Title::newFromText( $title );
00641         if ( is_null( $t ) || !$t->canTalk() ) {
00642             return '';
00643         }
00644         return wfEscapeWikiText( $t->getTalkPage()->getPrefixedText() );
00645     }
00646     public static function talkpagenamee( $parser, $title = null ) {
00647         $t = Title::newFromText( $title );
00648         if ( is_null( $t ) || !$t->canTalk() ) {
00649             return '';
00650         }
00651         return wfEscapeWikiText( $t->getTalkPage()->getPrefixedURL() );
00652     }
00653     public static function subjectpagename( $parser, $title = null ) {
00654         $t = Title::newFromText( $title );
00655         if ( is_null( $t ) ) {
00656             return '';
00657         }
00658         return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedText() );
00659     }
00660     public static function subjectpagenamee( $parser, $title = null ) {
00661         $t = Title::newFromText( $title );
00662         if ( is_null( $t ) ) {
00663             return '';
00664         }
00665         return wfEscapeWikiText( $t->getSubjectPage()->getPrefixedURL() );
00666     }
00667 
00678     public static function pagesincategory( $parser, $name = '', $arg1 = null, $arg2 = null ) {
00679         global $wgContLang;
00680         static $magicWords = null;
00681         if ( is_null( $magicWords ) ) {
00682             $magicWords = new MagicWordArray( array(
00683                 'pagesincategory_all',
00684                 'pagesincategory_pages',
00685                 'pagesincategory_subcats',
00686                 'pagesincategory_files'
00687             ) );
00688         }
00689         static $cache = array();
00690 
00691         // split the given option to its variable
00692         if ( self::matchAgainstMagicword( 'rawsuffix', $arg1 ) ) {
00693             //{{pagesincategory:|raw[|type]}}
00694             $raw = $arg1;
00695             $type = $magicWords->matchStartToEnd( $arg2 );
00696         } else {
00697             //{{pagesincategory:[|type[|raw]]}}
00698             $type = $magicWords->matchStartToEnd( $arg1 );
00699             $raw = $arg2;
00700         }
00701         if ( !$type ) { //backward compatibility
00702             $type = 'pagesincategory_all';
00703         }
00704 
00705         $title = Title::makeTitleSafe( NS_CATEGORY, $name );
00706         if ( !$title ) { # invalid title
00707             return self::formatRaw( 0, $raw );
00708         }
00709         $wgContLang->findVariantLink( $name, $title, true );
00710 
00711         // Normalize name for cache
00712         $name = $title->getDBkey();
00713 
00714         if ( !isset( $cache[$name] ) ) {
00715             $category = Category::newFromTitle( $title );
00716 
00717             $allCount = $subcatCount = $fileCount = $pagesCount = 0;
00718             if ( $parser->incrementExpensiveFunctionCount() ) {
00719                 // $allCount is the total number of cat members,
00720                 // not the count of how many members are normal pages.
00721                 $allCount = (int)$category->getPageCount();
00722                 $subcatCount = (int)$category->getSubcatCount();
00723                 $fileCount = (int)$category->getFileCount();
00724                 $pagesCount = $allCount - $subcatCount - $fileCount;
00725             }
00726             $cache[$name]['pagesincategory_all'] = $allCount;
00727             $cache[$name]['pagesincategory_pages'] = $pagesCount;
00728             $cache[$name]['pagesincategory_subcats'] = $subcatCount;
00729             $cache[$name]['pagesincategory_files'] = $fileCount;
00730         }
00731 
00732         $count = $cache[$name][$type];
00733         return self::formatRaw( $count, $raw );
00734     }
00735 
00745     public static function pagesize( $parser, $page = '', $raw = null ) {
00746         $title = Title::newFromText( $page );
00747 
00748         if ( !is_object( $title ) ) {
00749             return self::formatRaw( 0, $raw );
00750         }
00751 
00752         // fetch revision from cache/database and return the value
00753         $rev = self::getCachedRevisionObject( $parser, $title );
00754         $length = $rev ? $rev->getSize() : 0;
00755         return self::formatRaw( $length, $raw );
00756     }
00757 
00770     public static function protectionlevel( $parser, $type = '', $title = '' ) {
00771         $titleObject = Title::newFromText( $title );
00772         if ( !( $titleObject instanceof Title ) ) {
00773             $titleObject = $parser->mTitle;
00774         }
00775         if ( $titleObject->areRestrictionsLoaded() || $parser->incrementExpensiveFunctionCount() ) {
00776             $restrictions = $titleObject->getRestrictions( strtolower( $type ) );
00777             # Title::getRestrictions returns an array, its possible it may have
00778             # multiple values in the future
00779             return implode( $restrictions, ',' );
00780         }
00781         return '';
00782     }
00783 
00791     public static function language( $parser, $code = '', $inLanguage = '' ) {
00792         $code = strtolower( $code );
00793         $inLanguage = strtolower( $inLanguage );
00794         $lang = Language::fetchLanguageName( $code, $inLanguage );
00795         return $lang !== '' ? $lang : wfBCP47( $code );
00796     }
00797 
00807     public static function pad( $parser, $string, $length, $padding = '0', $direction = STR_PAD_RIGHT ) {
00808         $padding = $parser->killMarkers( $padding );
00809         $lengthOfPadding = mb_strlen( $padding );
00810         if ( $lengthOfPadding == 0 ) {
00811             return $string;
00812         }
00813 
00814         # The remaining length to add counts down to 0 as padding is added
00815         $length = min( $length, 500 ) - mb_strlen( $string );
00816         # $finalPadding is just $padding repeated enough times so that
00817         # mb_strlen( $string ) + mb_strlen( $finalPadding ) == $length
00818         $finalPadding = '';
00819         while ( $length > 0 ) {
00820             # If $length < $lengthofPadding, truncate $padding so we get the
00821             # exact length desired.
00822             $finalPadding .= mb_substr( $padding, 0, $length );
00823             $length -= $lengthOfPadding;
00824         }
00825 
00826         if ( $direction == STR_PAD_LEFT ) {
00827             return $finalPadding . $string;
00828         } else {
00829             return $string . $finalPadding;
00830         }
00831     }
00832 
00833     public static function padleft( $parser, $string = '', $length = 0, $padding = '0' ) {
00834         return self::pad( $parser, $string, $length, $padding, STR_PAD_LEFT );
00835     }
00836 
00837     public static function padright( $parser, $string = '', $length = 0, $padding = '0' ) {
00838         return self::pad( $parser, $string, $length, $padding );
00839     }
00840 
00846     public static function anchorencode( $parser, $text ) {
00847         $text = $parser->killMarkers( $text );
00848         return (string)substr( $parser->guessSectionNameFromWikiText( $text ), 1 );
00849     }
00850 
00851     public static function special( $parser, $text ) {
00852         list( $page, $subpage ) = SpecialPageFactory::resolveAlias( $text );
00853         if ( $page ) {
00854             $title = SpecialPage::getTitleFor( $page, $subpage );
00855             return $title->getPrefixedText();
00856         } else {
00857             // unknown special page, just use the given text as its title, if at all possible
00858             $title = Title::makeTitleSafe( NS_SPECIAL, $text );
00859             return $title ? $title->getPrefixedText() : self::special( $parser, 'Badtitle' );
00860         }
00861     }
00862 
00863     public static function speciale( $parser, $text ) {
00864         return wfUrlencode( str_replace( ' ', '_', self::special( $parser, $text ) ) );
00865     }
00866 
00875     public static function defaultsort( $parser, $text, $uarg = '' ) {
00876         static $magicWords = null;
00877         if ( is_null( $magicWords ) ) {
00878             $magicWords = new MagicWordArray( array( 'defaultsort_noerror', 'defaultsort_noreplace' ) );
00879         }
00880         $arg = $magicWords->matchStartToEnd( $uarg );
00881 
00882         $text = trim( $text );
00883         if ( strlen( $text ) == 0 ) {
00884             return '';
00885         }
00886         $old = $parser->getCustomDefaultSort();
00887         if ( $old === false || $arg !== 'defaultsort_noreplace' ) {
00888             $parser->setDefaultSort( $text );
00889         }
00890 
00891         if ( $old === false || $old == $text || $arg ) {
00892             return '';
00893         } else {
00894             $converter = $parser->getConverterLanguage()->getConverter();
00895             return '<span class="error">' .
00896                 wfMessage( 'duplicate-defaultsort',
00897                     // Message should be parsed, but these params should only be escaped.
00898                     $converter->markNoConversion( wfEscapeWikiText( $old ) ),
00899                     $converter->markNoConversion( wfEscapeWikiText( $text ) )
00900                 )->inContentLanguage()->text() .
00901                 '</span>';
00902         }
00903     }
00904 
00905     // Usage {{filepath|300}}, {{filepath|nowiki}}, {{filepath|nowiki|300}}
00906     // or {{filepath|300|nowiki}} or {{filepath|300px}}, {{filepath|200x300px}},
00907     // {{filepath|nowiki|200x300px}}, {{filepath|200x300px|nowiki}}.
00908     public static function filepath( $parser, $name = '', $argA = '', $argB = '' ) {
00909         $file = wfFindFile( $name );
00910 
00911         if ( $argA == 'nowiki' ) {
00912             // {{filepath: | option [| size] }}
00913             $isNowiki = true;
00914             $parsedWidthParam = $parser->parseWidthParam( $argB );
00915         } else {
00916             // {{filepath: [| size [|option]] }}
00917             $parsedWidthParam = $parser->parseWidthParam( $argA );
00918             $isNowiki = ( $argB == 'nowiki' );
00919         }
00920 
00921         if ( $file ) {
00922             $url = $file->getFullUrl();
00923 
00924             // If a size is requested...
00925             if ( count( $parsedWidthParam ) ) {
00926                 $mto = $file->transform( $parsedWidthParam );
00927                 // ... and we can
00928                 if ( $mto && !$mto->isError() ) {
00929                     // ... change the URL to point to a thumbnail.
00930                     $url = wfExpandUrl( $mto->getUrl(), PROTO_RELATIVE );
00931                 }
00932             }
00933             if ( $isNowiki ) {
00934                 return array( $url, 'nowiki' => true );
00935             }
00936             return $url;
00937         } else {
00938             return '';
00939         }
00940     }
00941 
00949     public static function tagObj( $parser, $frame, $args ) {
00950         if ( !count( $args ) ) {
00951             return '';
00952         }
00953         $tagName = strtolower( trim( $frame->expand( array_shift( $args ) ) ) );
00954 
00955         if ( count( $args ) ) {
00956             $inner = $frame->expand( array_shift( $args ) );
00957         } else {
00958             $inner = null;
00959         }
00960 
00961         $stripList = $parser->getStripList();
00962         if ( !in_array( $tagName, $stripList ) ) {
00963             return '<span class="error">' .
00964                 wfMessage( 'unknown_extension_tag', $tagName )->inContentLanguage()->text() .
00965                 '</span>';
00966         }
00967 
00968         $attributes = array();
00969         foreach ( $args as $arg ) {
00970             $bits = $arg->splitArg();
00971             if ( strval( $bits['index'] ) === '' ) {
00972                 $name = trim( $frame->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
00973                 $value = trim( $frame->expand( $bits['value'] ) );
00974                 if ( preg_match( '/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m ) ) {
00975                     $value = isset( $m[1] ) ? $m[1] : '';
00976                 }
00977                 $attributes[$name] = $value;
00978             }
00979         }
00980 
00981         $params = array(
00982             'name' => $tagName,
00983             'inner' => $inner,
00984             'attributes' => $attributes,
00985             'close' => "</$tagName>",
00986         );
00987         return $parser->extensionSubstitution( $params, $frame );
00988     }
00989 
01002     private static function getCachedRevisionObject( $parser, $title = null ) {
01003         static $cache = null;
01004         if ( $cache == null ) {
01005             $cache = new MapCacheLRU( 50 );
01006         }
01007 
01008         if ( is_null( $title ) ) {
01009             return null;
01010         }
01011 
01012         // Use the revision from the parser itself, when param is the current page
01013         // and the revision is the current one
01014         if ( $title->equals( $parser->getTitle() ) ) {
01015             $parserRev = $parser->getRevisionObject();
01016             if ( $parserRev && $parserRev->isCurrent() ) {
01017                 // force reparse after edit with vary-revision flag
01018                 $parser->getOutput()->setFlag( 'vary-revision' );
01019                 wfDebug( __METHOD__ . ": use current revision from parser, setting vary-revision...\n" );
01020                 return $parserRev;
01021             }
01022         }
01023 
01024         // Normalize name for cache
01025         $page = $title->getPrefixedDBkey();
01026 
01027         if ( $cache->has( $page ) ) { // cache contains null values
01028             return $cache->get( $page );
01029         }
01030         if ( $parser->incrementExpensiveFunctionCount() ) {
01031             $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
01032             $pageID = $rev ? $rev->getPage() : 0;
01033             $revID = $rev ? $rev->getId() : 0;
01034             $cache->set( $page, $rev ); // maybe null
01035 
01036             // Register dependency in templatelinks
01037             $parser->getOutput()->addTemplate( $title, $pageID, $revID );
01038 
01039             return $rev;
01040         }
01041         $cache->set( $page, null );
01042         return null;
01043     }
01044 
01052     public static function pageid( $parser, $title = null ) {
01053         $t = Title::newFromText( $title );
01054         if ( is_null( $t ) ) {
01055             return '';
01056         }
01057         // Use title from parser to have correct pageid after edit
01058         if ( $t->equals( $parser->getTitle() ) ) {
01059             $t = $parser->getTitle();
01060             return $t->getArticleID();
01061         }
01062 
01063         // These can't have ids
01064         if ( !$t->canExist() || $t->isExternal() ) {
01065             return 0;
01066         }
01067 
01068         // Check the link cache, maybe something already looked it up.
01069         $linkCache = LinkCache::singleton();
01070         $pdbk = $t->getPrefixedDBkey();
01071         $id = $linkCache->getGoodLinkID( $pdbk );
01072         if ( $id != 0 ) {
01073             $parser->mOutput->addLink( $t, $id );
01074             return $id;
01075         }
01076         if ( $linkCache->isBadLink( $pdbk ) ) {
01077             $parser->mOutput->addLink( $t, 0 );
01078             return $id;
01079         }
01080 
01081         // We need to load it from the DB, so mark expensive
01082         if ( $parser->incrementExpensiveFunctionCount() ) {
01083             $id = $t->getArticleID();
01084             $parser->mOutput->addLink( $t, $id );
01085             return $id;
01086         }
01087         return null;
01088     }
01089 
01097     public static function revisionid( $parser, $title = null ) {
01098         $t = Title::newFromText( $title );
01099         if ( is_null( $t ) ) {
01100             return '';
01101         }
01102         // fetch revision from cache/database and return the value
01103         $rev = self::getCachedRevisionObject( $parser, $t );
01104         return $rev ? $rev->getId() : '';
01105     }
01106 
01114     public static function revisionday( $parser, $title = null ) {
01115         $t = Title::newFromText( $title );
01116         if ( is_null( $t ) ) {
01117             return '';
01118         }
01119         // fetch revision from cache/database and return the value
01120         $rev = self::getCachedRevisionObject( $parser, $t );
01121         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'j' ) : '';
01122     }
01123 
01131     public static function revisionday2( $parser, $title = null ) {
01132         $t = Title::newFromText( $title );
01133         if ( is_null( $t ) ) {
01134             return '';
01135         }
01136         // fetch revision from cache/database and return the value
01137         $rev = self::getCachedRevisionObject( $parser, $t );
01138         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'd' ) : '';
01139     }
01140 
01148     public static function revisionmonth( $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 ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'm' ) : '';
01156     }
01157 
01165     public static function revisionmonth1( $parser, $title = null ) {
01166         $t = Title::newFromText( $title );
01167         if ( is_null( $t ) ) {
01168             return '';
01169         }
01170         // fetch revision from cache/database and return the value
01171         $rev = self::getCachedRevisionObject( $parser, $t );
01172         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'n' ) : '';
01173     }
01174 
01182     public static function revisionyear( $parser, $title = null ) {
01183         $t = Title::newFromText( $title );
01184         if ( is_null( $t ) ) {
01185             return '';
01186         }
01187         // fetch revision from cache/database and return the value
01188         $rev = self::getCachedRevisionObject( $parser, $t );
01189         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'Y' ) : '';
01190     }
01191 
01199     public static function revisiontimestamp( $parser, $title = null ) {
01200         $t = Title::newFromText( $title );
01201         if ( is_null( $t ) ) {
01202             return '';
01203         }
01204         // fetch revision from cache/database and return the value
01205         $rev = self::getCachedRevisionObject( $parser, $t );
01206         return $rev ? MWTimestamp::getLocalInstance( $rev->getTimestamp() )->format( 'YmdHis' ) : '';
01207     }
01208 
01216     public static function revisionuser( $parser, $title = null ) {
01217         $t = Title::newFromText( $title );
01218         if ( is_null( $t ) ) {
01219             return '';
01220         }
01221         // fetch revision from cache/database and return the value
01222         $rev = self::getCachedRevisionObject( $parser, $t );
01223         return $rev ? $rev->getUserText() : '';
01224     }
01225 
01238     public static function cascadingsources( $parser, $title = '' ) {
01239         $titleObject = Title::newFromText( $title );
01240         if ( !( $titleObject instanceof Title ) ) {
01241             $titleObject = $parser->mTitle;
01242         }
01243         if ( $titleObject->areCascadeProtectionSourcesLoaded()
01244             || $parser->incrementExpensiveFunctionCount()
01245         ) {
01246             $names = array();
01247             $sources = $titleObject->getCascadeProtectionSources();
01248             foreach ( $sources[0] as $sourceTitle ) {
01249                 $names[] = $sourceTitle->getPrefixedText();
01250             }
01251             return implode( $names, '|' );
01252         }
01253         return '';
01254     }
01255 
01256 }