Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F2978
Add_strings_to_ParserFunctions.patch
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Authored By
•
bzimport
Nov 21 2014, 9:18 PM
2014-11-21 21:18:47 (UTC+0)
Size
11 KB
Referenced Files
None
Subscribers
None
Add_strings_to_ParserFunctions.patch
View Options
Index: COPYING
===================================================================
--- COPYING (revision 46670)
+++ COPYING (working copy)
@@ -1,33 +1,8 @@
-The ParserFunctions extension may be copied and redistributed under either the
-DWTFYWWI license or the GNU General Public License, at the option of the
-licensee. The text of both licenses is given below.
+The ParserFunctions extension may be copied and redistributed under the GNU
+General Public License.
-The majority of this extension is written by (and copyright) Tim Starling. Minor
-modifications have been made by various members of the MediaWiki development
-team.
-
-------------------------------------------------------------------------------
- DWTFYWWI LICENSE
- Version 1, January 2006
-
- Copyright (C) 2006 Ævar Arnfjörð Bjarmason
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the DWTFYWWI or Do
-Whatever The Fuck You Want With It license is intended to guarantee
-your freedom to share and change the software--to make sure the
-software is free for all its users.
-
- DWTFYWWI LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-0. The author grants everyone permission to do whatever the fuck they
-want with the software, whatever the fuck that may be.
-
--------------------------------------------------------------------------------
-
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Index: ParserFunctions.i18n.magic.php
===================================================================
--- ParserFunctions.i18n.magic.php (revision 46670)
+++ ParserFunctions.i18n.magic.php (working copy)
@@ -25,6 +25,12 @@
'timel' => array( 0, 'timel' ),
'rel2abs' => array( 0, 'rel2abs' ),
'titleparts' => array( 0, 'titleparts' ),
+ 'len' => array( 0, 'len' ),
+ 'pos' => array( 0, 'pos' ),
+ 'rpos' => array( 0, 'rpos' ),
+ 'sub' => array( 0, 'sub' ),
+ 'replace' => array( 0, 'replace' ),
+ 'explode' => array( 0, 'explode' ),
);
/**
Index: ParserFunctions.i18n.php
===================================================================
--- ParserFunctions.i18n.php (revision 46670)
+++ ParserFunctions.i18n.php (working copy)
@@ -26,6 +26,7 @@
'pfunc_expr_invalid_argument_ln' => 'Invalid argument for ln: <= 0',
'pfunc_expr_unknown_error' => 'Expression error: Unknown error ($1)',
'pfunc_expr_not_a_number' => 'In $1: result is not a number',
+ 'pfunc_string_too_long' => 'Error: string exceeds $1 character limit',
);
/** Message documentation (Message documentation)
Index: ParserFunctions.php
===================================================================
--- ParserFunctions.php (revision 49109)
+++ ParserFunctions.php (working copy)
@@ -7,24 +7,33 @@
$wgExtensionFunctions[] = 'wfSetupParserFunctions';
$wgExtensionCredits['parserhook'][] = array(
'name' => 'ParserFunctions',
- 'version' => '1.1.1',
+ 'version' => '2.0.0',
'url' => 'http://www.mediawiki.org/wiki/Extension:ParserFunctions',
- 'author' => 'Tim Starling',
+ 'author' => array('Tim Starling', 'Robert Rohde', 'Ross McClure', 'Juraj Simlovic'),
'description' => 'Enhance parser with logical functions',
'descriptionmsg' => 'pfunc_desc',
);
$wgExtensionMessagesFiles['ParserFunctions'] = dirname(__FILE__) . '/ParserFunctions.i18n.php';
$wgHooks['LanguageGetMagic'][] = 'wfParserFunctionsLanguageGetMagic';
+$wgHooks['ParserAfterStrip'][] = 'ExtParserFunctions::loadRegex';
$wgParserTestFiles[] = dirname( __FILE__ ) . "/funcsParserTests.txt";
+//Defines the maximum length of a string that string functions are allowed to operate on
+//Prevention against DOS by string function.
+if( !isset($wgStringFunctionsLimit) ) {
+ $wgStringFunctionsLimit = 1000;
+}
+
class ExtParserFunctions {
var $mExprParser;
var $mTimeCache = array();
var $mTimeChars = 0;
var $mMaxTimeChars = 6000; # ~10 seconds
+ static $markerRegex = false;
+
function registerParser( &$parser ) {
if ( defined( get_class( $parser ) . '::SFH_OBJECT_ARGS' ) ) {
// These functions accept DOM-style arguments
@@ -49,6 +58,14 @@
$parser->setFunctionHook( 'rel2abs', array( &$this, 'rel2abs' ) );
$parser->setFunctionHook( 'titleparts', array( &$this, 'titleparts' ) );
+ //String Functions
+ $parser->setFunctionHook( 'len', array(&$this, 'runLen' ));
+ $parser->setFunctionHook( 'pos', array(&$this, 'runPos' ));
+ $parser->setFunctionHook( 'rpos', array(&$this, 'runRPos' ));
+ $parser->setFunctionHook( 'sub', array(&$this, 'runSub' ));
+ $parser->setFunctionHook( 'replace', array(&$this, 'runReplace' ));
+ $parser->setFunctionHook( 'explode', array(&$this, 'runExplode' ));
+
return true;
}
@@ -58,6 +75,36 @@
return true;
}
+ /* Called by ParserAfterStrip. Preloads the syntax for unique markers
+ so that we can avoid reconstructing it on every operation. */
+ static function loadRegex( &$parser ) {
+ wfProfileIn( __METHOD__ );
+
+ $prefix = preg_quote( $parser->mUniqPrefix, '/' );
+
+ if ( defined('Parser::MARKER_SUFFIX') )
+ $suffix = preg_quote( Parser::MARKER_SUFFIX, '/' );
+ elseif ( isset($parser->mMarkerSuffix) )
+ $suffix = preg_quote( $parser->mMarkerSuffix, '/' );
+ elseif ( defined('MW_PARSER_VERSION') && strcmp( MW_PARSER_VERSION, '1.6.1' ) > 0 )
+ $suffix = "QINU\x07";
+ else $suffix = 'QINU';
+
+ self::$markerRegex = '/' .$prefix. '(?:(?!' .$suffix. ').)*' . $suffix . '/us';
+
+ wfProfileOut( __METHOD__ );
+ return true;
+ }
+
+ // Removes unique markers from passed parameters, used by string functions.
+ private function killMarkers ( $text ) {
+ if( self::$markerRegex ) {
+ return preg_replace( self::$markerRegex , '' , $text );
+ } else {
+ return $text;
+ }
+ }
+
function &getExprParser() {
if ( !isset( $this->mExprParser ) ) {
if ( !class_exists( 'ExprParser' ) ) {
@@ -516,6 +563,188 @@
return $title;
}
}
+
+ // Verifies parameter is less than max string length.
+ private function checkLength( $text ) {
+ global $wgStringFunctionsLimit;
+ return ( mb_strlen( $text ) < $wgStringFunctionsLimit );
+ }
+
+ // Generates error message. Called when string is too long.
+ private function tooLongError() {
+ global $wgStringFunctionsLimit;
+ return wfMsg( 'pfunc_string_too_long', $wgStringFunctionsLimit );
+ }
+
+ /**
+ * {{#len:string}}
+ */
+ function runLen ( &$parser, $inStr = '' ) {
+ wfProfileIn( __METHOD__ );
+
+ $inStr = $this->killMarkers( (string)$inStr );
+ $len = mb_strlen( $inStr );
+
+ wfProfileOut( __METHOD__ );
+ return $len;
+ }
+
+ /**
+ * {{#pos:value|key|offset}}
+ * Note: If the needle is an empty string, single space is used instead.
+ * Note: If the needle is not found, -1 is returned.
+ */
+ function runPos ( &$parser, $inStr = '', $inNeedle = '', $inOffset = 0 ) {
+ wfProfileIn( __METHOD__ );
+
+ $inStr = $this->killMarkers( (string)$inStr );
+ $inNeedle = $this->killMarkers( (string)$inNeedle );
+
+ if( !$this->checkLength( $inStr ) ||
+ !$this->checkLength( $inNeedle ) ) {
+ wfProfileOut( __METHOD__ );
+ return $this->tooLongError();
+ }
+
+ if( $inNeedle == '' ) { $inNeedle = ' '; }
+
+ $pos = mb_strpos( $inStr, $inNeedle, $inOffset );
+ if( $pos === false ) { $pos = -1; }
+
+ wfProfileOut( __METHOD__ );
+ return $pos;
+ }
+
+ /**
+ * {{#rpos:value|key}}
+ * Note: If the needle is an empty string, single space is used instead.
+ * Note: If the needle is not found, -1 is returned.
+ */
+ function runRPos ( &$parser, $inStr = '', $inNeedle = '' ) {
+ wfProfileIn( __METHOD__ );
+
+ $inStr = $this->killMarkers( (string)$inStr );
+ $inNeedle = $this->killMarkers( (string)$inNeedle );
+
+ if( !$this->checkLength( $inStr ) ||
+ !$this->checkLength( $inNeedle ) ) {
+ wfProfileOut( __METHOD__ );
+ return $this->tooLongError();
+ }
+
+ if( $inNeedle == '' ) { $inNeedle = ' '; }
+
+ $pos = mb_strrpos( $inStr, $inNeedle );
+ if( $pos === false ) { $pos = -1; }
+
+ wfProfileOut( __METHOD__ );
+ return $pos;
+ }
+
+ /**
+ * {{#sub:value|start|length}}
+ * Note: If length is zero, the rest of the input is returned.
+ */
+ function runSub ( &$parser, $inStr = '', $inStart = 0, $inLength = 0 ) {
+ wfProfileIn( __METHOD__ );
+
+ $inStr = $this->killMarkers( (string)$inStr );
+
+ if( !$this->checkLength( $inStr ) ) {
+ wfProfileOut( __METHOD__ );
+ return $this->tooLongError();
+ }
+
+ if ( intval($inLength) == 0 ) {
+ $result = mb_substr( $inStr, $inStart );
+ } else {
+ $result = mb_substr( $inStr, $inStart, $inLength );
+ }
+
+ wfProfileOut( __METHOD__ );
+ return $result;
+ }
+
+ /**
+ * {{#replace:value|from|to}}
+ * Note: If "from" is an empty string, single space is used instead.
+ */
+ function runReplace( &$parser, $inStr = '', $inReplaceFrom = '', $inReplaceTo = '' ) {
+ global $wgStringFunctionsLimit;
+ wfProfileIn( __METHOD__ );
+
+ $inStr = $this->killMarkers( (string)$inStr );
+ $inReplaceFrom = $this->killMarkers( (string)$inReplaceFrom );
+ $inReplaceTo = $this->killMarkers( (string)$inReplaceTo );
+
+ if( !$this->checkLength( $inStr ) ||
+ !$this->checkLength( $inReplaceFrom ) ||
+ !$this->checkLength( $inReplaceTo ) ) {
+ wfProfileOut( __METHOD__ );
+ return $this->tooLongError();
+ }
+
+ if( $inReplaceFrom == '' ) { $inReplaceFrom = ' '; }
+
+ // Precompute limit to avoid generating enormous string:
+ $diff = mb_strlen( $inReplaceTo ) - mb_strlen( $inReplaceFrom );
+ if( $diff > 0 ) {
+ $limit = ( ( $wgStringFunctionsLimit - mb_strlen( $inStr ) ) / $diff ) + 1;
+ } else {
+ $limit = -1;
+ }
+
+ $inReplaceFrom = preg_quote( $inReplaceFrom, '/' );
+ $inReplaceTo = preg_quote( $inReplaceTo, '/' );
+
+ $result = preg_replace( '/' . $inReplaceFrom . '/u', $inReplaceTo, $inStr, $limit);
+
+ if( !$this->checkLength( $result ) ) {
+ wfProfileOut( __METHOD__ );
+ return $this->tooLongError();
+ }
+
+ wfProfileOut( __METHOD__ );
+ return $result;
+ }
+
+
+ /**
+ * {{#explode:value|delimiter|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 is not enough exploded chunks.
+ */
+ function runExplode ( &$parser, $inStr = '', $inDiv = '', $inPos = 0 ) {
+ wfProfileIn( __METHOD__ );
+
+ $inStr = $this->killMarkers( (string)$inStr );
+ $inDiv = $this->killMarkers( (string)$inDiv );
+
+ if( $inDiv == '' ) { $inDiv = ' '; }
+
+ $inStr = preg_quote( $inStr, '/' );
+ $inDiv = preg_quote( $inDiv, '/' );
+
+ if( !$this->checkLength( $inStr ) ||
+ !$this->checkLength( $inDiv ) ) {
+ wfProfileOut( __METHOD__ );
+ return $this->tooLongError();
+ }
+
+ $matches = preg_split( '/'.$inDiv.'/u', $inStr );
+
+ if( $inPos >= 0 && isset( $matches[$inPos] ) ) {
+ $result = $matches[$inPos];
+ } elseif ( $inPos < 0 && isset( $matches[count($matches) + $inPos] ) ) {
+ $result = $matches[count($matches) + $inPos];
+ } else {
+ $result = '';
+ }
+
+ wfProfileOut( __METHOD__ );
+ return $result;
+ }
}
function wfSetupParserFunctions() {
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2548
Default Alt Text
Add_strings_to_ParserFunctions.patch (11 KB)
Attached To
Mode
T8455: Set $wgPFEnableStringFunctions = true on WMF wikis
Attached
Detach File
Event Timeline
Log In to Comment