14 self::$mTimeChars = 0;
27 $wgHooks[
'ParserClearState'][] = __CLASS__ .
'::clearState';
36 if ( !isset( self::$mExprParser ) ) {
51 return '<strong class="error">' . htmlspecialchars(
$e->getMessage() ) .
'</strong>';
62 public static function ifexpr(
$parser, $expr =
'', $then =
'', $else =
'' ) {
65 if ( is_numeric(
$ret ) ) {
74 return '<strong class="error">' . htmlspecialchars(
$e->getMessage() ) .
'</strong>';
85 $expr = isset(
$args[0] ) ? trim( $frame->expand(
$args[0] ) ) :
'';
102 $test = isset(
$args[0] ) ? trim( $frame->expand(
$args[0] ) ) :
'';
103 if ( $test !==
'' ) {
104 return isset(
$args[1] ) ? trim( $frame->expand(
$args[1] ) ) :
'';
106 return isset(
$args[2] ) ? trim( $frame->expand(
$args[2] ) ) :
'';
122 if ( $left == $right ) {
123 return isset(
$args[2] ) ? trim( $frame->expand(
$args[2] ) ) :
'';
125 return isset(
$args[3] ) ? trim( $frame->expand(
$args[3] ) ) :
'';
136 public static function iferror(
$parser, $test =
'', $then =
'', $else =
false ) {
137 if ( preg_match(
'/<(?:strong|span|p|div)\s(?:[^\s>]*\s+)*?class="(?:[^"\s>]*\s+)*?error(?:\s[^">]*)?"/', $test ) ) {
139 } elseif ( $else ===
false ) {
153 $test = isset(
$args[0] ) ? trim( $frame->expand(
$args[0] ) ) :
'';
160 return trim( $frame->expand(
$result ) );
175 $found = $defaultFound =
false;
177 $lastItemHadNoEquals =
false;
181 $bits = $arg->splitArg();
182 $nameNode = $bits[
'name'];
183 $index = $bits[
'index'];
184 $valueNode = $bits[
'value'];
186 if ( $index ===
'' ) {
188 $lastItemHadNoEquals =
false;
190 # Multiple input match
191 return trim( $frame->expand( $valueNode ) );
195 if ( $test == $primary ) {
196 # Found a match, return now
197 return trim( $frame->expand( $valueNode ) );
198 } elseif ( $defaultFound || $mwDefault->matchStartToEnd( $test ) ) {
199 $default = $valueNode;
200 $defaultFound =
false;
201 } #
else wrong
case,
continue
204 # Multiple input, single output
205 # If the value matches, set a flag and continue
206 $lastItemHadNoEquals =
true;
210 if ( $decodedTest == $primary ) {
212 } elseif ( $mwDefault->matchStartToEnd( $decodedTest ) ) {
213 $defaultFound =
true;
218 # Check if the last item had no = sign, thus specifying the default case
219 if ( $lastItemHadNoEquals ) {
221 } elseif ( !is_null( $default ) ) {
222 return trim( $frame->expand( $default ) );
243 $from = trim( $from );
244 if ( $from ===
'' ) {
245 $from =
$parser->getTitle()->getPrefixedText();
248 $to = rtrim( $to ,
' /' );
251 if ( $to ===
'' || $to ===
'.' ) {
256 if ( substr( $to , 0 , 1 ) !==
'/' &&
257 substr( $to , 0 , 2 ) !==
'./' &&
258 substr( $to , 0 , 3 ) !==
'../' &&
264 $fullPath =
'/' . $from .
'/' . $to .
'/';
267 $fullPath = preg_replace(
'!/(\./)+!',
'/', $fullPath );
270 $fullPath = preg_replace(
'!/{2,}!',
'/', $fullPath );
273 $fullPath = trim( $fullPath ,
'/' );
274 $exploded = explode (
'/' , $fullPath );
275 $newExploded =
array();
277 foreach ( $exploded
as $current ) {
278 if ( $current ===
'..' ) {
279 if ( !
count( $newExploded ) ) {
281 $msg =
wfMessage(
'pfunc_rel2abs_invalid_depth', $fullPath )->inContentLanguage()->escaped();
282 return '<strong class="error">' . $msg .
'</strong>';
285 array_pop( $newExploded );
288 $newExploded[] = $current;
293 return implode(
'/' , $newExploded );
314 if ( !
$parser->incrementExpensiveFunctionCount() ) {
322 $file->getName(), $file->getTimestamp(), $file->getSha1() );
323 return $file->exists() ? $then : $else;
330 } elseif (
$title->isExternal() ) {
337 $pdbk =
$title->getPrefixedDBkey();
339 $id = $lc->getGoodLinkID( $pdbk );
343 } elseif ( $lc->isBadLink( $pdbk ) ) {
347 if ( !
$parser->incrementExpensiveFunctionCount() ) {
350 $id =
$title->getArticleID();
377 return trim( $frame->expand(
$result ) );
390 public static function timeCommon(
$parser, $frame =
null, $format =
'', $date =
'', $language =
'', $local =
false ) {
393 if ( $date ===
'' ) {
394 $cacheKey =
$parser->getOptions()->getTimestamp();
396 $date = $timestamp->getTimestamp( TS_ISO_8601 );
402 if ( isset( self::$mTimeCache[$format][$cacheKey][$language][$local] ) ) {
403 $cachedVal = self::$mTimeCache[$format][$cacheKey][$language][$local];
404 if ( $useTTL && $cachedVal[1] !==
null && $frame && is_callable(
array( $frame,
'setTTL' ) ) ) {
405 $frame->setTTL( $cachedVal[1] );
407 return $cachedVal[0];
410 # compute the timestamp string $ts
411 # PHP >= 5.2 can handle dates before 1970 or after 2038 using the DateTime object
413 $invalidTime =
false;
415 # the DateTime constructor must be used because it throws exceptions
416 # when errors occur, whereas date_create appears to just output a warning
417 # that can't really be detected from within the code
420 # Default input timezone is UTC.
421 $utc =
new DateTimeZone(
'UTC' );
423 # Correct for DateTime interpreting 'XXXX' as XX:XX o'clock
424 if ( preg_match(
'/^[0-9]{4}$/', $date ) ) {
425 $date =
'00:00 '.$date;
429 # UTC is a default input timezone.
430 $dateObject =
new DateTime( $date, $utc );
432 # Set output timezone.
434 if ( isset( $wgLocaltimezone ) ) {
435 $tz =
new DateTimeZone( $wgLocaltimezone );
437 $tz =
new DateTimeZone( date_default_timezone_get() );
442 $dateObject->setTimezone( $tz );
444 $ts = $dateObject->format(
'YmdHis' );
446 }
catch ( Exception $ex ) {
451 # format the timestamp and return the result
452 if ( $invalidTime ) {
453 $result =
'<strong class="error">' .
wfMessage(
'pfunc_time_error' )->inContentLanguage()->escaped() .
'</strong>';
455 self::$mTimeChars += strlen( $format );
456 if ( self::$mTimeChars > self::$mMaxTimeChars ) {
457 return '<strong class="error">' .
wfMessage(
'pfunc_time_too_long' )->inContentLanguage()->escaped() .
'</strong>';
460 return '<strong class="error">' .
wfMessage(
'pfunc_time_too_small' )->inContentLanguage()->escaped() .
'</strong>';
461 } elseif ( $ts < 100000000000000 ) {
467 $langObject =
$parser->getFunctionLang();
470 $result = $langObject->sprintfDate( $format, $ts, $tz, $ttl );
472 return '<strong class="error">' .
wfMessage(
'pfunc_time_too_big' )->inContentLanguage()->escaped() .
'</strong>';
476 self::$mTimeCache[$format][$cacheKey][$language][$local] =
array(
$result, $ttl );
477 if ( $useTTL && $ttl !==
null && $frame && is_callable(
array( $frame,
'setTTL' ) ) ) {
478 $frame->setTTL( $ttl );
491 public static function time(
$parser, $format =
'', $date =
'', $language =
'', $local =
false ) {
503 $format = isset(
$args[0] ) ? trim( $frame->expand(
$args[0] ) ) :
'';
504 $date = isset(
$args[1] ) ? trim( $frame->expand(
$args[1] ) ) :
'';
505 $language = isset(
$args[2] ) ? trim( $frame->expand(
$args[2] ) ) :
'';
506 $local = isset(
$args[3] ) && trim( $frame->expand(
$args[3] ) );
528 $format = isset(
$args[0] ) ? trim( $frame->expand(
$args[0] ) ) :
'';
529 $date = isset(
$args[1] ) ? trim( $frame->expand(
$args[1] ) ) :
'';
530 $language = isset(
$args[2] ) ? trim( $frame->expand(
$args[2] ) ) :
'';
545 $parts = (int)$parts;
546 $offset = (int)$offset;
548 if ( $ntitle instanceof
Title ) {
549 $bits = explode(
'/', $ntitle->getPrefixedText(), 25 );
550 if (
count( $bits ) <= 0 ) {
551 return $ntitle->getPrefixedText();
556 if ( $parts === 0 ) {
557 return implode(
'/', array_slice( $bits, $offset ) );
559 return implode(
'/', array_slice( $bits, $offset, $parts ) );
573 global $wgPFStringLengthLimit;
574 return ( mb_strlen( $text ) < $wgPFStringLengthLimit );
582 global $wgPFStringLengthLimit;
583 $msg =
wfMessage(
'pfunc_string_too_long' )->numParams( $wgPFStringLengthLimit );
584 return '<strong class="error">' . $msg->inContentLanguage()->escaped() .
'</strong>';
596 $inStr =
$parser->killMarkers( (
string)$inStr );
597 return mb_strlen( $inStr );
613 public static function runPos (
$parser, $inStr =
'', $inNeedle =
'', $inOffset = 0 ) {
614 $inStr =
$parser->killMarkers( (
string)$inStr );
615 $inNeedle =
$parser->killMarkers( (
string)$inNeedle );
617 if ( !self::checkLength( $inStr ) ||
618 !self::checkLength( $inNeedle ) ) {
622 if ( $inNeedle ===
'' ) { $inNeedle =
' '; }
624 $pos = mb_strpos( $inStr, $inNeedle, (
int)$inOffset );
625 if ( $pos ===
false ) { $pos =
''; }
643 $inStr =
$parser->killMarkers( (
string)$inStr );
644 $inNeedle =
$parser->killMarkers( (
string)$inNeedle );
646 if ( !self::checkLength( $inStr ) ||
647 !self::checkLength( $inNeedle ) ) {
651 if ( $inNeedle ===
'' ) { $inNeedle =
' '; }
653 $pos = mb_strrpos( $inStr, $inNeedle );
654 if ( $pos ===
false ) { $pos = -1; }
677 public static function runSub (
$parser, $inStr =
'', $inStart = 0, $inLength = 0 ) {
678 $inStr =
$parser->killMarkers( (
string)$inStr );
680 if ( !self::checkLength( $inStr ) ) {
684 if ( (
int)$inLength === 0 ) {
685 $result = mb_substr( $inStr, (
int)$inStart );
687 $result = mb_substr( $inStr, (
int)$inStart, (
int)$inLength );
705 $inStr =
$parser->killMarkers( (
string)$inStr );
706 $inSubStr =
$parser->killMarkers( (
string)$inSubStr );
708 if ( !self::checkLength( $inStr ) ||
709 !self::checkLength( $inSubStr ) ) {
713 if ( $inSubStr ===
'' ) {
717 $result = mb_substr_count( $inStr, $inSubStr );
738 $inReplaceFrom =
'', $inReplaceTo =
'', $inLimit = -1 ) {
739 global $wgPFStringLengthLimit;
741 $inStr =
$parser->killMarkers( (
string)$inStr );
742 $inReplaceFrom =
$parser->killMarkers( (
string)$inReplaceFrom );
743 $inReplaceTo =
$parser->killMarkers( (
string)$inReplaceTo );
745 if ( !self::checkLength( $inStr ) ||
746 !self::checkLength( $inReplaceFrom ) ||
747 !self::checkLength( $inReplaceTo ) ) {
751 if ( $inReplaceFrom ===
'' ) { $inReplaceFrom =
' '; }
754 $diff = mb_strlen( $inReplaceTo ) - mb_strlen( $inReplaceFrom );
756 $limit = ( ( $wgPFStringLengthLimit - mb_strlen( $inStr ) ) / $diff ) + 1;
761 $inLimit = (int)$inLimit;
762 if ( $inLimit >= 0 ) {
769 $inReplaceFrom = preg_quote( $inReplaceFrom,
'/' );
772 $result = preg_replace(
'/' . $inReplaceFrom .
'/u',
773 $inReplaceTo, $inStr,
$limit );
775 if ( !self::checkLength(
$result ) ) {
799 public static function runExplode (
$parser, $inStr =
'', $inDiv =
'', $inPos = 0, $inLim =
null ) {
800 $inStr =
$parser->killMarkers( (
string)$inStr );
801 $inDiv =
$parser->killMarkers( (
string)$inDiv );
803 if ( $inDiv ===
'' ) {
807 if ( !self::checkLength( $inStr ) ||
808 !self::checkLength( $inDiv ) ) {
812 $inDiv = preg_quote( $inDiv,
'/' );
814 $matches = preg_split(
'/' . $inDiv .
'/u', $inStr, $inLim );
816 if ( $inPos >= 0 && isset(
$matches[$inPos] ) ) {
836 $inStr =
$parser->killMarkers( (
string)$inStr );
837 if ( !self::checkLength( $inStr ) ) {
841 return urldecode( $inStr );
856 $expanded = $frame->expand( $obj );
857 $trimExpanded = trim( $expanded );
858 return trim( Sanitizer::decodeCharReferences( $expanded ) );