2009-06-05 09:53:05 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
class ExtParserFunctions {
|
2011-04-11 17:27:51 +00:00
|
|
|
static $mExprParser;
|
|
|
|
static $mTimeCache = array();
|
|
|
|
static $mTimeChars = 0;
|
|
|
|
static $mMaxTimeChars = 6000; # ~10 seconds
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @return bool
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function clearState( $parser ) {
|
|
|
|
self::$mTimeChars = 0;
|
2009-06-05 09:53:05 +00:00
|
|
|
$parser->pf_markerRegex = null;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
/**
|
|
|
|
* Register ParserClearState hook.
|
|
|
|
* We defer this until needed to avoid the loading of the code of this file
|
|
|
|
* when no parser function is actually called.
|
|
|
|
*/
|
|
|
|
public static function registerClearHook() {
|
|
|
|
static $done = false;
|
|
|
|
if( !$done ) {
|
|
|
|
global $wgHooks;
|
|
|
|
$wgHooks['ParserClearState'][] = __CLASS__ . '::clearState';
|
|
|
|
$done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-05 09:53:05 +00:00
|
|
|
/**
|
|
|
|
* Get the marker regex. Cached.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser Parser
|
|
|
|
* @return
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function getMarkerRegex( $parser ) {
|
|
|
|
self::registerClearHook();
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( isset( $parser->pf_markerRegex ) ) {
|
|
|
|
return $parser->pf_markerRegex;
|
|
|
|
}
|
|
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
|
|
$prefix = preg_quote( $parser->uniqPrefix(), '/' );
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
$suffix = preg_quote( Parser::MARKER_SUFFIX, '/' );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
|
|
|
$parser->pf_markerRegex = '/' . $prefix . '(?:(?!' . $suffix . ').)*' . $suffix . '/us';
|
2009-06-05 09:53:05 +00:00
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
return $parser->pf_markerRegex;
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $text string
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
private static function killMarkers ( $parser, $text ) {
|
|
|
|
return preg_replace( self::getMarkerRegex( $parser ), '' , $text );
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
2011-01-14 00:40:30 +00:00
|
|
|
/**
|
|
|
|
* @return ExprParser
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function &getExprParser() {
|
|
|
|
if ( !isset( self::$mExprParser ) ) {
|
|
|
|
self::$mExprParser = new ExprParser;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::$mExprParser;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $expr string
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function expr( $parser, $expr = '' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
try {
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::getExprParser()->doExpression( $expr );
|
2010-10-02 22:36:34 +00:00
|
|
|
} catch ( ExprError $e ) {
|
2014-04-08 16:04:32 +00:00
|
|
|
return '<strong class="error">' . htmlspecialchars( $e->getMessage() ) . '</strong>';
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $expr string
|
|
|
|
* @param $then string
|
|
|
|
* @param $else string
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function ifexpr( $parser, $expr = '', $then = '', $else = '' ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
try {
|
2011-04-11 17:27:51 +00:00
|
|
|
$ret = self::getExprParser()->doExpression( $expr );
|
2010-03-18 11:35:28 +00:00
|
|
|
if ( is_numeric( $ret ) ) {
|
|
|
|
$ret = floatval( $ret );
|
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $ret ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
return $then;
|
|
|
|
} else {
|
|
|
|
return $else;
|
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
} catch ( ExprError $e ) {
|
2014-04-08 16:04:32 +00:00
|
|
|
return '<strong class="error">' . htmlspecialchars( $e->getMessage() ) . '</strong>';
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args array
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function ifexprObj( $parser, $frame, $args ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$expr = isset( $args[0] ) ? trim( $frame->expand( $args[0] ) ) : '';
|
|
|
|
$then = isset( $args[1] ) ? $args[1] : '';
|
|
|
|
$else = isset( $args[2] ) ? $args[2] : '';
|
2011-04-11 17:27:51 +00:00
|
|
|
$result = self::ifexpr( $parser, $expr, $then, $else );
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( is_object( $result ) ) {
|
|
|
|
$result = trim( $frame->expand( $result ) );
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args array
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function ifObj( $parser, $frame, $args ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$test = isset( $args[0] ) ? trim( $frame->expand( $args[0] ) ) : '';
|
|
|
|
if ( $test !== '' ) {
|
|
|
|
return isset( $args[1] ) ? trim( $frame->expand( $args[1] ) ) : '';
|
|
|
|
} else {
|
|
|
|
return isset( $args[2] ) ? trim( $frame->expand( $args[2] ) ) : '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args array
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function ifeqObj( $parser, $frame, $args ) {
|
2014-02-15 03:26:30 +00:00
|
|
|
$left = isset( $args[0] ) ? self::decodeTrimExpand( $args[0], $frame ) : '';
|
|
|
|
$right = isset( $args[1] ) ? self::decodeTrimExpand( $args[1], $frame ) : '';
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( $left == $right ) {
|
|
|
|
return isset( $args[2] ) ? trim( $frame->expand( $args[2] ) ) : '';
|
|
|
|
} else {
|
|
|
|
return isset( $args[3] ) ? trim( $frame->expand( $args[3] ) ) : '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $test string
|
|
|
|
* @param $then string
|
|
|
|
* @param $else bool
|
|
|
|
* @return bool|string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function iferror( $parser, $test = '', $then = '', $else = false ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( preg_match( '/<(?:strong|span|p|div)\s(?:[^\s>]*\s+)*?class="(?:[^"\s>]*\s+)*?error(?:\s[^">]*)?"/', $test ) ) {
|
|
|
|
return $then;
|
|
|
|
} elseif ( $else === false ) {
|
|
|
|
return $test;
|
|
|
|
} else {
|
|
|
|
return $else;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args array
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function iferrorObj( $parser, $frame, $args ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$test = isset( $args[0] ) ? trim( $frame->expand( $args[0] ) ) : '';
|
|
|
|
$then = isset( $args[1] ) ? $args[1] : false;
|
|
|
|
$else = isset( $args[2] ) ? $args[2] : false;
|
2011-04-11 17:27:51 +00:00
|
|
|
$result = self::iferror( $parser, $test, $then, $else );
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( $result === false ) {
|
|
|
|
return '';
|
|
|
|
} else {
|
|
|
|
return trim( $frame->expand( $result ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-15 17:44:19 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function switchObj( $parser, $frame, $args ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( count( $args ) == 0 ) {
|
|
|
|
return '';
|
|
|
|
}
|
2014-02-15 03:26:30 +00:00
|
|
|
$primary = self::decodeTrimExpand( array_shift( $args ), $frame );
|
2009-06-05 16:53:59 +00:00
|
|
|
$found = $defaultFound = false;
|
2009-06-05 09:53:05 +00:00
|
|
|
$default = null;
|
|
|
|
$lastItemHadNoEquals = false;
|
2014-02-15 03:26:30 +00:00
|
|
|
$lastItem = '';
|
2009-06-05 09:53:05 +00:00
|
|
|
$mwDefault =& MagicWord::get( 'default' );
|
|
|
|
foreach ( $args as $arg ) {
|
|
|
|
$bits = $arg->splitArg();
|
|
|
|
$nameNode = $bits['name'];
|
|
|
|
$index = $bits['index'];
|
|
|
|
$valueNode = $bits['value'];
|
|
|
|
|
|
|
|
if ( $index === '' ) {
|
|
|
|
# Found "="
|
|
|
|
$lastItemHadNoEquals = false;
|
|
|
|
if ( $found ) {
|
|
|
|
# Multiple input match
|
|
|
|
return trim( $frame->expand( $valueNode ) );
|
|
|
|
} else {
|
2014-02-15 03:26:30 +00:00
|
|
|
$test = self::decodeTrimExpand( $nameNode, $frame );
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( $test == $primary ) {
|
|
|
|
# Found a match, return now
|
|
|
|
return trim( $frame->expand( $valueNode ) );
|
2014-07-11 18:14:36 +00:00
|
|
|
} elseif ( $defaultFound || $mwDefault->matchStartToEnd( $test ) ) {
|
2009-06-05 16:31:43 +00:00
|
|
|
$default = $valueNode;
|
2013-10-05 01:49:54 +00:00
|
|
|
$defaultFound = false;
|
2009-06-05 16:31:43 +00:00
|
|
|
} # else wrong case, continue
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
# Multiple input, single output
|
|
|
|
# If the value matches, set a flag and continue
|
|
|
|
$lastItemHadNoEquals = true;
|
2014-02-15 03:26:30 +00:00
|
|
|
// $lastItem is an "out" variable
|
|
|
|
$decodedTest = self::decodeTrimExpand( $valueNode, $frame, $lastItem );
|
|
|
|
if ( $decodedTest == $primary ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$found = true;
|
2014-07-11 18:14:36 +00:00
|
|
|
} elseif ( $mwDefault->matchStartToEnd( $decodedTest ) ) {
|
2009-06-05 16:53:59 +00:00
|
|
|
$defaultFound = true;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# Default case
|
|
|
|
# Check if the last item had no = sign, thus specifying the default case
|
|
|
|
if ( $lastItemHadNoEquals ) {
|
2014-02-15 03:26:30 +00:00
|
|
|
return $lastItem;
|
2009-06-05 09:53:05 +00:00
|
|
|
} elseif ( !is_null( $default ) ) {
|
|
|
|
return trim( $frame->expand( $default ) );
|
|
|
|
} else {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the absolute path to a subpage, relative to the current article
|
|
|
|
* title. Treats titles as slash-separated paths.
|
|
|
|
*
|
|
|
|
* Following subpage link syntax instead of standard path syntax, an
|
|
|
|
* initial slash is treated as a relative path, and vice versa.
|
2011-04-15 17:44:19 +00:00
|
|
|
*
|
|
|
|
* @param $parser Parser
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $to string
|
|
|
|
* @param $from string
|
|
|
|
*
|
|
|
|
* @return string
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function rel2abs( $parser , $to = '' , $from = '' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2010-10-02 22:36:34 +00:00
|
|
|
$from = trim( $from );
|
|
|
|
if ( $from == '' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$from = $parser->getTitle()->getPrefixedText();
|
|
|
|
}
|
|
|
|
|
|
|
|
$to = rtrim( $to , ' /' );
|
|
|
|
|
|
|
|
// if we have an empty path, or just one containing a dot
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $to == '' || $to == '.' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
return $from;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the path isn't relative
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( substr( $to , 0 , 1 ) != '/' &&
|
|
|
|
substr( $to , 0 , 2 ) != './' &&
|
|
|
|
substr( $to , 0 , 3 ) != '../' &&
|
2009-06-05 09:53:05 +00:00
|
|
|
$to != '..' )
|
|
|
|
{
|
|
|
|
$from = '';
|
|
|
|
}
|
|
|
|
// Make a long path, containing both, enclose it in /.../
|
|
|
|
$fullPath = '/' . $from . '/' . $to . '/';
|
|
|
|
|
|
|
|
// remove redundant current path dots
|
|
|
|
$fullPath = preg_replace( '!/(\./)+!', '/', $fullPath );
|
|
|
|
|
|
|
|
// remove double slashes
|
|
|
|
$fullPath = preg_replace( '!/{2,}!', '/', $fullPath );
|
|
|
|
|
|
|
|
// remove the enclosing slashes now
|
|
|
|
$fullPath = trim( $fullPath , '/' );
|
|
|
|
$exploded = explode ( '/' , $fullPath );
|
|
|
|
$newExploded = array();
|
|
|
|
|
|
|
|
foreach ( $exploded as $current ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $current == '..' ) { // removing one level
|
|
|
|
if ( !count( $newExploded ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
// attempted to access a node above root node
|
2012-09-07 23:12:24 +00:00
|
|
|
$msg = wfMessage( 'pfunc_rel2abs_invalid_depth', $fullPath )->inContentLanguage()->escaped();
|
|
|
|
return '<strong class="error">' . $msg . '</strong>';
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
// remove last level from the stack
|
|
|
|
array_pop( $newExploded );
|
|
|
|
} else {
|
|
|
|
// add the current level to the stack
|
|
|
|
$newExploded[] = $current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// we can now join it again
|
|
|
|
return implode( '/' , $newExploded );
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $titletext string
|
|
|
|
* @param $then string
|
|
|
|
* @param $else string
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function ifexistCommon( $parser, $frame, $titletext = '', $then = '', $else = '' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
global $wgContLang;
|
|
|
|
$title = Title::newFromText( $titletext );
|
|
|
|
$wgContLang->findVariantLink( $titletext, $title, true );
|
|
|
|
if ( $title ) {
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $title->getNamespace() == NS_MEDIA ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
/* If namespace is specified as NS_MEDIA, then we want to
|
|
|
|
* check the physical file, not the "description" page.
|
|
|
|
*/
|
2012-09-08 18:05:50 +00:00
|
|
|
if ( !$parser->incrementExpensiveFunctionCount() ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
return $else;
|
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
$file = wfFindFile( $title );
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( !$file ) {
|
|
|
|
return $else;
|
|
|
|
}
|
2011-04-04 01:22:08 +00:00
|
|
|
$parser->mOutput->addImage(
|
|
|
|
$file->getName(), $file->getTimestamp(), $file->getSha1() );
|
2009-06-05 09:53:05 +00:00
|
|
|
return $file->exists() ? $then : $else;
|
2010-10-02 22:36:34 +00:00
|
|
|
} elseif ( $title->getNamespace() == NS_SPECIAL ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
/* Don't bother with the count for special pages,
|
|
|
|
* since their existence can be checked without
|
|
|
|
* accessing the database.
|
|
|
|
*/
|
2012-07-23 19:55:59 +00:00
|
|
|
return SpecialPageFactory::exists( $title->getDBkey() ) ? $then : $else;
|
2010-10-02 22:36:34 +00:00
|
|
|
} elseif ( $title->isExternal() ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
/* Can't check the existence of pages on other sites,
|
|
|
|
* so just return $else. Makes a sort of sense, since
|
|
|
|
* they don't exist _locally_.
|
|
|
|
*/
|
|
|
|
return $else;
|
|
|
|
} else {
|
|
|
|
$pdbk = $title->getPrefixedDBkey();
|
2011-12-18 19:00:53 +00:00
|
|
|
$lc = LinkCache::singleton();
|
|
|
|
$id = $lc->getGoodLinkID( $pdbk );
|
|
|
|
if ( $id != 0 ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$parser->mOutput->addLink( $title, $id );
|
|
|
|
return $then;
|
|
|
|
} elseif ( $lc->isBadLink( $pdbk ) ) {
|
|
|
|
$parser->mOutput->addLink( $title, 0 );
|
|
|
|
return $else;
|
|
|
|
}
|
2013-05-28 17:13:24 +00:00
|
|
|
if ( !$parser->incrementExpensiveFunctionCount() ) {
|
|
|
|
return $else;
|
|
|
|
}
|
2009-06-05 09:53:05 +00:00
|
|
|
$id = $title->getArticleID();
|
|
|
|
$parser->mOutput->addLink( $title, $id );
|
|
|
|
if ( $id ) {
|
|
|
|
return $then;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $else;
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args array
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function ifexistObj( $parser, $frame, $args ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$title = isset( $args[0] ) ? trim( $frame->expand( $args[0] ) ) : '';
|
|
|
|
$then = isset( $args[1] ) ? $args[1] : null;
|
|
|
|
$else = isset( $args[2] ) ? $args[2] : null;
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$result = self::ifexistCommon( $parser, $frame, $title, $then, $else );
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( $result === null ) {
|
|
|
|
return '';
|
|
|
|
} else {
|
|
|
|
return trim( $frame->expand( $result ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
2014-06-01 02:43:36 +00:00
|
|
|
* @param $frame PPFrame
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $format string
|
|
|
|
* @param $date string
|
|
|
|
* @param $language string
|
|
|
|
* @param $local string|bool
|
|
|
|
* @return string
|
|
|
|
*/
|
2014-06-01 02:43:36 +00:00
|
|
|
public static function timeCommon( $parser, $frame = null, $format = '', $date = '', $language = '', $local = false ) {
|
2011-12-19 00:54:31 +00:00
|
|
|
global $wgLocaltimezone;
|
2011-04-11 17:27:51 +00:00
|
|
|
self::registerClearHook();
|
2011-12-19 11:18:13 +00:00
|
|
|
if ( $date === '' ) {
|
|
|
|
$cacheKey = $parser->getOptions()->getTimestamp();
|
2012-09-07 23:12:24 +00:00
|
|
|
$timestamp = new MWTimestamp( $cacheKey );
|
|
|
|
$date = $timestamp->getTimestamp( TS_ISO_8601 );
|
2014-06-01 02:43:36 +00:00
|
|
|
$useTTL = true;
|
2011-12-19 11:18:13 +00:00
|
|
|
} else {
|
|
|
|
$cacheKey = $date;
|
2014-06-01 02:43:36 +00:00
|
|
|
$useTTL = false;
|
2011-12-19 11:18:13 +00:00
|
|
|
}
|
|
|
|
if ( isset( self::$mTimeCache[$format][$cacheKey][$language][$local] ) ) {
|
2014-06-01 02:43:36 +00:00
|
|
|
$cachedVal = self::$mTimeCache[$format][$cacheKey][$language][$local];
|
|
|
|
if ( $useTTL && $cachedVal[1] !== null && $frame && is_callable( array( $frame, 'setTTL' ) ) ) {
|
|
|
|
$frame->setTTL( $cachedVal[1] );
|
|
|
|
}
|
|
|
|
return $cachedVal[0];
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
|
|
|
|
# compute the timestamp string $ts
|
|
|
|
# PHP >= 5.2 can handle dates before 1970 or after 2038 using the DateTime object
|
|
|
|
|
2009-06-05 09:53:05 +00:00
|
|
|
$invalidTime = false;
|
2010-10-02 22:36:34 +00:00
|
|
|
|
2011-12-19 10:51:39 +00:00
|
|
|
# the DateTime constructor must be used because it throws exceptions
|
|
|
|
# when errors occur, whereas date_create appears to just output a warning
|
|
|
|
# that can't really be detected from within the code
|
|
|
|
try {
|
2011-12-07 20:52:41 +00:00
|
|
|
|
2011-12-19 10:51:39 +00:00
|
|
|
# Default input timezone is UTC.
|
|
|
|
$utc = new DateTimeZone( 'UTC' );
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2011-12-19 10:51:39 +00:00
|
|
|
# Correct for DateTime interpreting 'XXXX' as XX:XX o'clock
|
|
|
|
if ( preg_match( '/^[0-9]{4}$/', $date ) ) {
|
|
|
|
$date = '00:00 '.$date;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
2011-12-19 10:51:39 +00:00
|
|
|
|
|
|
|
# Parse date
|
2011-12-19 11:18:13 +00:00
|
|
|
# UTC is a default input timezone.
|
|
|
|
$dateObject = new DateTime( $date, $utc );
|
|
|
|
|
2011-12-19 10:51:39 +00:00
|
|
|
# Set output timezone.
|
|
|
|
if ( $local ) {
|
|
|
|
if ( isset( $wgLocaltimezone ) ) {
|
|
|
|
$tz = new DateTimeZone( $wgLocaltimezone );
|
|
|
|
} else {
|
|
|
|
$tz = new DateTimeZone( date_default_timezone_get() );
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
2011-12-19 10:51:39 +00:00
|
|
|
} else {
|
2013-03-22 16:52:31 +00:00
|
|
|
$tz = $utc;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
2013-03-22 16:52:31 +00:00
|
|
|
$dateObject->setTimezone( $tz );
|
2011-12-19 10:51:39 +00:00
|
|
|
# Generate timestamp
|
|
|
|
$ts = $dateObject->format( 'YmdHis' );
|
|
|
|
|
|
|
|
} catch ( Exception $ex ) {
|
|
|
|
$invalidTime = true;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
|
2014-06-01 02:43:36 +00:00
|
|
|
$ttl = null;
|
2010-10-02 22:36:34 +00:00
|
|
|
# format the timestamp and return the result
|
2009-06-05 09:53:05 +00:00
|
|
|
if ( $invalidTime ) {
|
2012-09-07 23:12:24 +00:00
|
|
|
$result = '<strong class="error">' . wfMessage( 'pfunc_time_error' )->inContentLanguage()->escaped() . '</strong>';
|
2009-06-05 09:53:05 +00:00
|
|
|
} else {
|
2011-04-11 17:27:51 +00:00
|
|
|
self::$mTimeChars += strlen( $format );
|
|
|
|
if ( self::$mTimeChars > self::$mMaxTimeChars ) {
|
2012-09-07 23:12:24 +00:00
|
|
|
return '<strong class="error">' . wfMessage( 'pfunc_time_too_long' )->inContentLanguage()->escaped() . '</strong>';
|
2009-06-05 09:53:05 +00:00
|
|
|
} else {
|
2013-04-19 21:24:48 +00:00
|
|
|
if ( $ts < 0 ) { // Language can't deal with BC years
|
|
|
|
return '<strong class="error">' . wfMessage( 'pfunc_time_too_small' )->inContentLanguage()->escaped() . '</strong>';
|
|
|
|
} elseif ( $ts < 100000000000000 ) { // Language can't deal with years after 9999
|
2011-09-27 22:47:20 +00:00
|
|
|
if ( $language !== '' && Language::isValidBuiltInCode( $language ) ) {
|
2011-07-19 20:29:17 +00:00
|
|
|
// use whatever language is passed as a parameter
|
2011-05-02 22:21:56 +00:00
|
|
|
$langObject = Language::factory( $language );
|
2011-07-19 20:29:17 +00:00
|
|
|
} else {
|
|
|
|
// use wiki's content language
|
2014-07-03 19:26:40 +00:00
|
|
|
$langObject = $parser->getFunctionLang();
|
|
|
|
StubObject::unstub( $langObject ); // $ttl is passed by reference, which doesn't work right on stub objects
|
2011-05-02 22:21:56 +00:00
|
|
|
}
|
2014-07-03 19:26:40 +00:00
|
|
|
$result = $langObject->sprintfDate( $format, $ts, $tz, $ttl );
|
2011-05-02 22:21:56 +00:00
|
|
|
} else {
|
2012-09-07 23:12:24 +00:00
|
|
|
return '<strong class="error">' . wfMessage( 'pfunc_time_too_big' )->inContentLanguage()->escaped() . '</strong>';
|
2011-04-26 00:26:12 +00:00
|
|
|
}
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-01 02:43:36 +00:00
|
|
|
self::$mTimeCache[$format][$cacheKey][$language][$local] = array( $result, $ttl );
|
|
|
|
if ( $useTTL && $ttl !== null && $frame && is_callable( array( $frame, 'setTTL' ) ) ) {
|
|
|
|
$frame->setTTL( $ttl );
|
|
|
|
}
|
2009-06-05 09:53:05 +00:00
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2014-06-01 02:43:36 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $format string
|
|
|
|
* @param $date string
|
|
|
|
* @param $language string
|
|
|
|
* @param $local string|bool
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function time( $parser, $format = '', $date = '', $language = '', $local = false ) {
|
|
|
|
return self::timeCommon( $parser, null, $format, $date, $language, $local );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args array
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function timeObj( $parser, $frame, $args ) {
|
|
|
|
$format = isset( $args[0] ) ? trim( $frame->expand( $args[0] ) ) : '';
|
|
|
|
$date = isset( $args[1] ) ? trim( $frame->expand( $args[1] ) ) : '';
|
|
|
|
$language = isset( $args[2] ) ? trim( $frame->expand( $args[2] ) ) : '';
|
|
|
|
$local = isset( $args[3] ) && trim( $frame->expand( $args[3] ) );
|
|
|
|
return self::timeCommon( $parser, $frame, $format, $date, $language, $local );
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $format string
|
|
|
|
* @param $date string
|
|
|
|
* @param $language string
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-26 00:26:12 +00:00
|
|
|
public static function localTime( $parser, $format = '', $date = '', $language = '' ) {
|
2014-06-01 02:43:36 +00:00
|
|
|
return self::timeCommon( $parser, null, $format, $date, $language, true );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param $args array
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function localTimeObj( $parser, $frame, $args ) {
|
|
|
|
$format = isset( $args[0] ) ? trim( $frame->expand( $args[0] ) ) : '';
|
|
|
|
$date = isset( $args[1] ) ? trim( $frame->expand( $args[1] ) ) : '';
|
|
|
|
$language = isset( $args[2] ) ? trim( $frame->expand( $args[2] ) ) : '';
|
|
|
|
return self::timeCommon( $parser, $frame, $format, $date, $language, true );
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Obtain a specified number of slash-separated parts of a title,
|
|
|
|
* e.g. {{#titleparts:Hello/World|1}} => "Hello"
|
|
|
|
*
|
2012-07-23 19:55:59 +00:00
|
|
|
* @param $parser Parser Parent parser
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $title string Title to split
|
|
|
|
* @param $parts int Number of parts to keep
|
|
|
|
* @param $offset int Offset starting at 1
|
2009-06-05 09:53:05 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function titleparts( $parser, $title = '', $parts = 0, $offset = 0 ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$parts = intval( $parts );
|
|
|
|
$offset = intval( $offset );
|
|
|
|
$ntitle = Title::newFromText( $title );
|
|
|
|
if ( $ntitle instanceof Title ) {
|
|
|
|
$bits = explode( '/', $ntitle->getPrefixedText(), 25 );
|
|
|
|
if ( count( $bits ) <= 0 ) {
|
|
|
|
return $ntitle->getPrefixedText();
|
|
|
|
} else {
|
|
|
|
if ( $offset > 0 ) {
|
|
|
|
--$offset;
|
|
|
|
}
|
|
|
|
if ( $parts == 0 ) {
|
|
|
|
return implode( '/', array_slice( $bits, $offset ) );
|
|
|
|
} else {
|
|
|
|
return implode( '/', array_slice( $bits, $offset, $parts ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return $title;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* Verifies parameter is less than max string length.
|
|
|
|
* @param $text
|
|
|
|
* @return bool
|
|
|
|
*/
|
2011-04-13 14:17:43 +00:00
|
|
|
private static function checkLength( $text ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
global $wgPFStringLengthLimit;
|
|
|
|
return ( mb_strlen( $text ) < $wgPFStringLengthLimit );
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
/**
|
|
|
|
* Generates error message. Called when string is too long.
|
|
|
|
* @return string
|
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
private static function tooLongError() {
|
2012-09-07 23:12:24 +00:00
|
|
|
global $wgPFStringLengthLimit;
|
|
|
|
$msg = wfMessage( 'pfunc_string_too_long' )->numParams( $wgPFStringLengthLimit );
|
|
|
|
return '<strong class="error">' . $msg->inContentLanguage()->escaped() . '</strong>';
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {{#len:string}}
|
2010-10-02 22:36:34 +00:00
|
|
|
*
|
2009-06-05 09:53:05 +00:00
|
|
|
* Reports number of characters in string.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser Parser
|
|
|
|
* @param $inStr string
|
|
|
|
* @return int
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runLen ( $parser, $inStr = '' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
2009-06-05 09:53:05 +00:00
|
|
|
$len = mb_strlen( $inStr );
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
return $len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {{#pos: string | needle | offset}}
|
|
|
|
*
|
|
|
|
* Finds first occurrence of "needle" in "string" starting at "offset".
|
|
|
|
*
|
|
|
|
* Note: If the needle is an empty string, single space is used instead.
|
|
|
|
* Note: If the needle is not found, empty string is returned.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser Parser
|
|
|
|
* @param $inStr string
|
2012-07-23 19:55:59 +00:00
|
|
|
* @param $inNeedle int|string
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $inOffset int
|
|
|
|
* @return int|string
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runPos ( $parser, $inStr = '', $inNeedle = '', $inOffset = 0 ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
|
|
|
$inNeedle = self::killMarkers( $parser, (string)$inNeedle );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
if ( !self::checkLength( $inStr ) ||
|
2012-02-06 04:37:05 +00:00
|
|
|
!self::checkLength( $inNeedle ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $inNeedle == '' ) { $inNeedle = ' '; }
|
2009-06-05 09:53:05 +00:00
|
|
|
|
|
|
|
$pos = mb_strpos( $inStr, $inNeedle, $inOffset );
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $pos === false ) { $pos = ""; }
|
2009-06-05 09:53:05 +00:00
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
return $pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {{#rpos: string | needle}}
|
|
|
|
*
|
|
|
|
* Finds last occurrence of "needle" in "string".
|
|
|
|
*
|
|
|
|
* Note: If the needle is an empty string, single space is used instead.
|
|
|
|
* Note: If the needle is not found, -1 is returned.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser Parser
|
|
|
|
* @param $inStr string
|
2012-07-23 19:55:59 +00:00
|
|
|
* @param $inNeedle int|string
|
2011-12-19 00:54:31 +00:00
|
|
|
* @return int|string
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runRPos ( $parser, $inStr = '', $inNeedle = '' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
|
|
|
$inNeedle = self::killMarkers( $parser, (string)$inNeedle );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
if ( !self::checkLength( $inStr ) ||
|
2012-02-06 04:37:05 +00:00
|
|
|
!self::checkLength( $inNeedle ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $inNeedle == '' ) { $inNeedle = ' '; }
|
2009-06-05 09:53:05 +00:00
|
|
|
|
|
|
|
$pos = mb_strrpos( $inStr, $inNeedle );
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $pos === false ) { $pos = -1; }
|
2009-06-05 09:53:05 +00:00
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
return $pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {{#sub: string | start | length }}
|
|
|
|
*
|
|
|
|
* Returns substring of "string" starting at "start" and having
|
2010-10-02 22:36:34 +00:00
|
|
|
* "length" characters.
|
2009-06-05 09:53:05 +00:00
|
|
|
*
|
|
|
|
* Note: If length is zero, the rest of the input is returned.
|
2010-10-02 22:36:34 +00:00
|
|
|
* Note: A negative value for "start" operates from the end of the
|
2009-06-05 09:53:05 +00:00
|
|
|
* "string".
|
|
|
|
* Note: A negative value for "length" returns a string reduced in
|
|
|
|
* length by that amount.
|
2011-12-19 00:54:31 +00:00
|
|
|
*
|
|
|
|
* @param $parser Parser
|
|
|
|
* @param $inStr string
|
|
|
|
* @param $inStart int
|
|
|
|
* @param $inLength int
|
|
|
|
* @return string
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runSub ( $parser, $inStr = '', $inStart = 0, $inLength = 0 ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
if ( !self::checkLength( $inStr ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
|
|
|
|
if ( intval( $inLength ) == 0 ) {
|
2014-01-31 16:03:50 +00:00
|
|
|
$result = mb_substr( $inStr, intval( $inStart ) );
|
2009-06-05 09:53:05 +00:00
|
|
|
} else {
|
2011-11-21 21:18:18 +00:00
|
|
|
$result = mb_substr( $inStr, intval( $inStart ), intval( $inLength ) );
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2010-10-02 22:36:34 +00:00
|
|
|
return $result;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {{#count: string | substr }}
|
|
|
|
*
|
|
|
|
* Returns number of occurrences of "substr" in "string".
|
|
|
|
*
|
|
|
|
* Note: If "substr" is empty, a single space is used.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser
|
|
|
|
* @param $inStr string
|
|
|
|
* @param $inSubStr string
|
|
|
|
* @return int|string
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runCount ( $parser, $inStr = '', $inSubStr = '' ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
|
|
|
$inSubStr = self::killMarkers( $parser, (string)$inSubStr );
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
if ( !self::checkLength( $inStr ) ||
|
2011-12-19 00:54:31 +00:00
|
|
|
!self::checkLength( $inSubStr ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
if ( $inSubStr == '' ) {
|
|
|
|
$inSubStr = ' ';
|
|
|
|
}
|
2010-10-02 22:36:34 +00:00
|
|
|
|
2009-06-05 09:53:05 +00:00
|
|
|
$result = mb_substr_count( $inStr, $inSubStr );
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2010-10-02 22:36:34 +00:00
|
|
|
return $result;
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {{#replace:string | from | to | limit }}
|
|
|
|
*
|
|
|
|
* Replaces each occurrence of "from" in "string" with "to".
|
|
|
|
* At most "limit" replacements are performed.
|
2010-10-02 22:36:34 +00:00
|
|
|
*
|
2009-06-05 09:53:05 +00:00
|
|
|
* Note: Armored against replacements that would generate huge strings.
|
|
|
|
* Note: If "from" is an empty string, single space is used instead.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser Parser
|
|
|
|
* @param $inStr string
|
|
|
|
* @param $inReplaceFrom string
|
|
|
|
* @param $inReplaceTo string
|
|
|
|
* @param $inLimit int
|
|
|
|
* @return mixed|string
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runReplace( $parser, $inStr = '',
|
2009-06-05 09:53:05 +00:00
|
|
|
$inReplaceFrom = '', $inReplaceTo = '', $inLimit = -1 ) {
|
|
|
|
global $wgPFStringLengthLimit;
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
|
|
|
$inReplaceFrom = self::killMarkers( $parser, (string)$inReplaceFrom );
|
|
|
|
$inReplaceTo = self::killMarkers( $parser, (string)$inReplaceTo );
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
if ( !self::checkLength( $inStr ) ||
|
2012-02-06 04:37:05 +00:00
|
|
|
!self::checkLength( $inReplaceFrom ) ||
|
|
|
|
!self::checkLength( $inReplaceTo ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $inReplaceFrom == '' ) { $inReplaceFrom = ' '; }
|
2009-06-05 09:53:05 +00:00
|
|
|
|
|
|
|
// Precompute limit to avoid generating enormous string:
|
|
|
|
$diff = mb_strlen( $inReplaceTo ) - mb_strlen( $inReplaceFrom );
|
2010-10-02 22:36:34 +00:00
|
|
|
if ( $diff > 0 ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$limit = ( ( $wgPFStringLengthLimit - mb_strlen( $inStr ) ) / $diff ) + 1;
|
|
|
|
} else {
|
|
|
|
$limit = -1;
|
|
|
|
}
|
|
|
|
|
2010-10-02 22:36:34 +00:00
|
|
|
$inLimit = intval( $inLimit );
|
|
|
|
if ( $inLimit >= 0 ) {
|
|
|
|
if ( $limit > $inLimit || $limit == -1 ) { $limit = $inLimit; }
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Use regex to allow limit and handle UTF-8 correctly.
|
|
|
|
$inReplaceFrom = preg_quote( $inReplaceFrom, '/' );
|
2010-01-27 11:25:23 +00:00
|
|
|
$inReplaceTo = StringUtils::escapeRegexReplacement( $inReplaceTo );
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2010-10-02 22:36:34 +00:00
|
|
|
$result = preg_replace( '/' . $inReplaceFrom . '/u',
|
|
|
|
$inReplaceTo, $inStr, $limit );
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
if ( !self::checkLength( $result ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2010-08-08 16:18:33 +00:00
|
|
|
* {{#explode:string | delimiter | position | limit}}
|
2009-06-05 09:53:05 +00:00
|
|
|
*
|
|
|
|
* Breaks "string" into chunks separated by "delimiter" and returns the
|
|
|
|
* chunk identified by "position".
|
|
|
|
*
|
|
|
|
* Note: Negative position can be used to specify tokens from the end.
|
|
|
|
* Note: If the divider is an empty string, single space is used instead.
|
|
|
|
* Note: Empty string is returned if there are not enough exploded chunks.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser Parser
|
|
|
|
* @param $inStr string
|
|
|
|
* @param $inDiv string
|
|
|
|
* @param $inPos int
|
|
|
|
* @param $inLim int|null
|
|
|
|
* @return string
|
2009-06-05 09:53:05 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runExplode ( $parser, $inStr = '', $inDiv = '', $inPos = 0, $inLim = null ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
|
|
|
$inDiv = self::killMarkers( $parser, (string)$inDiv );
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2011-12-19 00:54:31 +00:00
|
|
|
if ( $inDiv == '' ) {
|
|
|
|
$inDiv = ' ';
|
|
|
|
}
|
2009-06-05 09:53:05 +00:00
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
if ( !self::checkLength( $inStr ) ||
|
2012-02-06 04:37:05 +00:00
|
|
|
!self::checkLength( $inDiv ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$inDiv = preg_quote( $inDiv, '/' );
|
2010-10-02 22:36:34 +00:00
|
|
|
|
|
|
|
$matches = preg_split( '/' . $inDiv . '/u', $inStr, $inLim );
|
|
|
|
|
|
|
|
if ( $inPos >= 0 && isset( $matches[$inPos] ) ) {
|
2009-06-05 09:53:05 +00:00
|
|
|
$result = $matches[$inPos];
|
2010-10-02 22:36:34 +00:00
|
|
|
} elseif ( $inPos < 0 && isset( $matches[count( $matches ) + $inPos] ) ) {
|
|
|
|
$result = $matches[count( $matches ) + $inPos];
|
2009-06-05 09:53:05 +00:00
|
|
|
} else {
|
|
|
|
$result = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
return $result;
|
|
|
|
}
|
2010-05-29 16:12:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* {{#urldecode:string}}
|
|
|
|
*
|
|
|
|
* Decodes URL-encoded (like%20that) strings.
|
2011-12-19 00:54:31 +00:00
|
|
|
* @param $parser Parser
|
|
|
|
* @param $inStr string
|
|
|
|
* @return string
|
2010-05-29 16:12:41 +00:00
|
|
|
*/
|
2011-04-11 17:27:51 +00:00
|
|
|
public static function runUrlDecode( $parser, $inStr = '' ) {
|
2010-05-29 16:12:41 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
2011-04-11 17:27:51 +00:00
|
|
|
$inStr = self::killMarkers( $parser, (string)$inStr );
|
|
|
|
if ( !self::checkLength( $inStr ) ) {
|
2010-05-29 16:12:41 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-04-11 17:27:51 +00:00
|
|
|
return self::tooLongError();
|
2010-05-29 16:12:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$result = urldecode( $inStr );
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
return $result;
|
|
|
|
}
|
2014-02-15 03:26:30 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Take a PPNode (-ish thing), expand it, remove entities, and trim.
|
|
|
|
*
|
|
|
|
* For use when doing string comparisions, where user expects entities
|
|
|
|
* to be equal for what they stand for (e.g. comparisions with {{PAGENAME}})
|
|
|
|
*
|
|
|
|
* @param $obj PPNode|string Thing to expand
|
|
|
|
* @param $frame PPFrame
|
|
|
|
* @param &$trimExpanded String Expanded and trimmed version of PPNode, but with char refs intact
|
|
|
|
* @return String The trimmed, expanded and entity reference decoded version of the PPNode
|
|
|
|
*/
|
|
|
|
private static function decodeTrimExpand( $obj, $frame, &$trimExpanded = null ) {
|
|
|
|
$expanded = $frame->expand( $obj );
|
|
|
|
$trimExpanded = trim( $expanded );
|
|
|
|
return trim( Sanitizer::decodeCharReferences( $expanded ) );
|
|
|
|
}
|
2009-06-05 09:53:05 +00:00
|
|
|
}
|