Index: trunk/extensions/RegexFun/RELEASE-NOTES |
— | — | @@ -1,10 +1,14 @@ |
2 | 2 | Changelog: |
3 | 3 | ========== |
4 | | - * (trunk) 2011 -- version 1.0.1 |
5 | | - - Bug in '#regex_var' solved: default value now gets returned in case '#regex' went wront or |
| 4 | + * November 6, 2011 -- Version 1.0.1 |
| 5 | + - Bug in '#regex_var' solved: default value now gets returned in case '#regex' went wrong or |
6 | 6 | not called before. |
7 | | - - '#regexall' last parameter, 'length' can be empty '' which is the specified default now. It |
8 | | - simply means there is not limit and all items should be returned. |
| 7 | + - '#regexall' last parameter, 'length', can be empty '' which is the specified default now. It |
| 8 | + simply means there is no limit and all items should be returned ('-1' has another meaning). |
| 9 | + - Introduces two global configuration variables: |
| 10 | + + '$egRegexFunDisabledFunctions' - to disable certain functions within the wiki. |
| 11 | + + '$egRegexFunMaxRegexPerParse' - limit for number of function calls per parser process. |
| 12 | + - Some minor cleanup done. |
9 | 13 | |
10 | 14 | * November 4, 2011 -- Version 1.0 (initial public release). |
11 | 15 | Introduces the following parser functions defined within 'ExtRegexFun' class: |
— | — | @@ -18,22 +22,22 @@ |
19 | 23 | - Replacing within strings, using regular expression. |
20 | 24 | - Allows save use of user input within expressions by running '#regexquote' parser function |
21 | 25 | over it. An important function other regex extensions still lack. |
22 | | - - Allows to get the last '#regex' subexpression matches via '#regex_var', even allows to |
| 26 | + - Allows to get the last '#regex' sub-expression matches via '#regex_var', even allows to |
23 | 27 | get them in an extensive way, e.g. "$0 has $2, $1 and $3". |
24 | 28 | - Invalid regex will result in an inline error message instead of php notice as some other |
25 | 29 | regex extensions might do it. |
26 | | - - Efficient regex validation allowing all kinds of delimitiers and flags but filtering 'e' |
| 30 | + - Efficient regex validation allowing all kinds of delimiters and flags but filtering 'e' |
27 | 31 | flag for security reasons in any case... |
28 | 32 | - ... therefore, original 'e' flag instead has another but very similar meaning adjusted for |
29 | | - a mediawiki context. Instead of executing php code within the replacement string, the 'e' |
| 33 | + a MediaWiki context. Instead of executing php code within the replacement string, the 'e' |
30 | 34 | flag now causes the replacement string to be parsed after references ('$1', '\1') are |
31 | 35 | replaced. This allows stuff like "{{((}}Template{{!}}$1{{))}}" within the replacement. |
32 | 36 | |
33 | 37 | Changes since earlier versions (trunk and earlier, non-public): |
34 | 38 | - '#regexsearch' parser function removed. Instead there is a special flag 'r' now which leads |
35 | 39 | to the same result if #regex and replacement is being used: '' as output if nothing replaced. |
36 | | - - '#regexascii' parser function removed. Instead '#regexquote' will make an ascii-quote MW |
37 | | - special characters ';' and '#' if they are first character in the string. |
| 40 | + - '#regexascii' parser function removed. Instead '#regexquote' will ascii-quote MW special |
| 41 | + characters ';' and '#' if they are first character in the string. |
38 | 42 | - '#regexquote' delimiter set to '/' by default. |
39 | 43 | - '#regex' no longer returns its value as parsed wikitext (option 'noparse' => false) instead |
40 | 44 | the 'e' flag can be used (although not exactly the same). |
Index: trunk/extensions/RegexFun/RegexFun.i18n.php |
— | — | @@ -18,6 +18,7 @@ |
19 | 19 | $messages['en'] = array( |
20 | 20 | 'regexfun-desc' => 'Adds parser functions allowing the use of regular expressions within wiki pages', |
21 | 21 | 'regexfun-invalid' => 'The regular expression "$1" is invalid.', |
| 22 | + 'regexfun-limit-exceed' => 'Maximum of $1 "Regex Fun" regular expression handlings reached.', |
22 | 23 | ); |
23 | 24 | |
24 | 25 | /** German (Deutsch) |
— | — | @@ -26,6 +27,7 @@ |
27 | 28 | $messages['de'] = array( |
28 | 29 | 'regexfun-desc' => 'Fügt Parser-Funktionen hinzu, um reguläre Ausdrücke auf Wiki-Seiten verwenden zu können', |
29 | 30 | 'regexfun-invalid' => '„$1“ ist kein gültiger regulärer Ausdruck.', |
| 31 | + 'regexfun-limit-exceed' => 'Maximale Anzahl von $1 durch „Regex Fun“ behandelte reguläre Ausdrücke erreicht.', |
30 | 32 | ); |
31 | 33 | |
32 | 34 | /** Galician (Galego) |
Index: trunk/extensions/RegexFun/RegexFun.php |
— | — | @@ -20,6 +20,7 @@ |
21 | 21 | |
22 | 22 | if ( ! defined( 'MEDIAWIKI' ) ) { die( ); } |
23 | 23 | |
| 24 | + |
24 | 25 | /**** extension info ****/ |
25 | 26 | |
26 | 27 | $wgExtensionCredits['parserhook'][] = array( |
— | — | @@ -36,7 +37,10 @@ |
37 | 38 | |
38 | 39 | $wgHooks['ParserFirstCallInit'][] = 'ExtRegexFun::init'; |
39 | 40 | $wgHooks['ParserClearState' ][] = 'ExtRegexFun::onParserClearState'; |
| 41 | +$wgHooks['ParserLimitReport' ][] = 'ExtRegexFun::onParserLimitReport'; |
40 | 42 | |
| 43 | +// Include the settings file: |
| 44 | +require_once ExtRegexFun::getDir() . '/RegexFun_Settings.php'; |
41 | 45 | |
42 | 46 | /** |
43 | 47 | * Extension class with all the regex functions functionality |
— | — | @@ -54,18 +58,29 @@ |
55 | 59 | */ |
56 | 60 | const VERSION = '1.0.1'; |
57 | 61 | |
58 | | - /** |
59 | | - * Sets up parser functions |
60 | | - */ |
61 | | - public static function init( &$parser ) { |
62 | | - $parser->setFunctionHook( 'regex', array( __CLASS__, 'regex' ) ); |
63 | | - $parser->setFunctionHook( 'regex_var', array( __CLASS__, 'regex_var' ) ); |
64 | | - $parser->setFunctionHook( 'regexall', array( __CLASS__, 'regexall' ) ); |
65 | | - $parser->setFunctionHook( 'regexquote', array( __CLASS__, 'regexquote' ) ); |
66 | | - $parser->setFunctionHook( 'regexascii', array( __CLASS__, 'regexascii' ) ); |
| 62 | + /** |
| 63 | + * Sets up parser functions |
| 64 | + */ |
| 65 | + public static function init( Parser &$parser ) { |
| 66 | + self::initFunction( $parser, 'regex' ); |
| 67 | + self::initFunction( $parser, 'regex_var' ); |
| 68 | + self::initFunction( $parser, 'regexquote' ); |
| 69 | + self::initFunction( $parser, 'regexall' ); |
67 | 70 | |
68 | 71 | return true; |
69 | | - } |
| 72 | + } |
| 73 | + private static function initFunction( Parser &$parser, $name, $functionCallback = null ) { |
| 74 | + if( $functionCallback === null ) { |
| 75 | + $functionCallback = array( __CLASS__, $name ); |
| 76 | + } |
| 77 | + |
| 78 | + global $egRegexFunDisabledFunctions; |
| 79 | + |
| 80 | + // only register function if not disabled by configuration |
| 81 | + if( ! in_array( $name, $egRegexFunDisabledFunctions ) ) { |
| 82 | + $parser->setFunctionHook( $name, $functionCallback ); |
| 83 | + } |
| 84 | + } |
70 | 85 | |
71 | 86 | /** |
72 | 87 | * Returns the extensions base installation directory. |
— | — | @@ -94,6 +109,7 @@ |
95 | 110 | */ |
96 | 111 | private static $tmpRegexCB; |
97 | 112 | |
| 113 | + |
98 | 114 | /** |
99 | 115 | * Checks whether the given regular expression is valid or would cause an error. |
100 | 116 | * Also alters the pattern in case it would be a security risk and communicates |
— | — | @@ -179,6 +195,15 @@ |
180 | 196 | return false; |
181 | 197 | } |
182 | 198 | |
| 199 | + private static function limitHandler( Parser &$parser ) { |
| 200 | + // is the limit exceeded for this parsers parse() process? |
| 201 | + if( self::limitExceeded( $parser ) ) { |
| 202 | + return false; |
| 203 | + } |
| 204 | + self::increaseRegexCount( $parser ); |
| 205 | + return true; |
| 206 | + } |
| 207 | + |
183 | 208 | /** |
184 | 209 | * Returns a valid parser function output that the given pattern is not valid for a regular |
185 | 210 | * expression. The message can be displayed in the wiki and is wrapped in an error-class span |
— | — | @@ -188,11 +213,17 @@ |
189 | 214 | * |
190 | 215 | * @return Array |
191 | 216 | */ |
192 | | - public static function invalidRegexParsingOutput( $pattern ) { |
193 | | - $msg = '<span class="error">' . wfMsgExt( 'regexfun-invalid', array( 'content' ), "<tt><nowiki>$pattern</nowiki></tt>" ). '</span>'; |
194 | | - return array( $msg, 'noparse' => true, 'isHTML' => false ); // isHTML must be false for #iferror! |
| 217 | + protected static function msgInvalidRegex( $pattern ) { |
| 218 | + $msg = '<span class="error">' . wfMsgForContent( 'regexfun-invalid', "<tt><nowiki>$pattern</nowiki></tt>" ). '</span>'; |
| 219 | + return array( $msg, 'noparse' => false, 'isHTML' => false ); // 'noparse' true for <nowiki>, 'isHTML' false for #iferror! |
195 | 220 | } |
196 | 221 | |
| 222 | + protected static function msgLimitExceeded() { |
| 223 | + global $egRegexFunMaxRegexPerParse; |
| 224 | + $msg = '<span class="error">' . wfMsgForContent( 'regexfun-limit-exceed', $egRegexFunMaxRegexPerParse ). '</span>'; |
| 225 | + return array( $msg, 'noparse' => true, 'isHTML' => false ); // 'isHTML' must be false for #iferror! |
| 226 | + } |
| 227 | + |
197 | 228 | /** |
198 | 229 | * Helper function. Validates regex and takes care of security risks in pattern which is why |
199 | 230 | * the pattern is taken by reference! |
— | — | @@ -212,21 +243,26 @@ |
213 | 244 | } |
214 | 245 | |
215 | 246 | /** |
216 | | - * Performs a regular expression search or replacement |
| 247 | + * Performs a regular expression search or replacement |
217 | 248 | * |
218 | | - * @param $parser Parser instance of running Parse |
219 | | - * @param $subject String input string to evaluate |
220 | | - * @param $pattern String regular expression pattern - must use /, | or % delimiter |
221 | | - * @param $replace String regular expression replacement |
| 249 | + * @param $parser Parser instance of running Parse |
| 250 | + * @param $subject String input string to evaluate |
| 251 | + * @param $pattern String regular expression pattern - must use /, | or % delimiter |
| 252 | + * @param $replace String regular expression replacement |
222 | 253 | * |
223 | | - * @return String Result of replacing pattern with replacement in string, or matching text if replacement was omitted |
224 | | - */ |
| 254 | + * @return String Result of replacing pattern with replacement in string, or matching text if replacement was omitted |
| 255 | + */ |
225 | 256 | public static function regex( Parser &$parser, $subject = '', $pattern = '', $replace = null, $limit = -1 ) { |
| 257 | + // check whether limit exceeded: |
| 258 | + if( self::limitExceeded( $parser ) ) { |
| 259 | + return self::msgLimitExceeded(); |
| 260 | + } |
| 261 | + self::increaseRegexCount( $parser ); |
226 | 262 | |
227 | 263 | // validate, initialise and check for wrong input: |
228 | 264 | $continue = self::validateRegexCall( $parser, $subject, $pattern, $specialFlags, true ); |
229 | 265 | if( ! $continue ) { |
230 | | - return self::invalidRegexParsingOutput( $pattern );; |
| 266 | + return self::msgInvalidRegex( $pattern ); |
231 | 267 | } |
232 | 268 | |
233 | 269 | if( $replace === null ) { |
— | — | @@ -302,11 +338,17 @@ |
303 | 339 | * |
304 | 340 | * @return String result of all matching text parts separated by a string |
305 | 341 | */ |
306 | | - public static function regexall( &$parser , $subject = '' , $pattern = '' , $separator = ', ' , $offset = 0 , $length = '' ) { |
| 342 | + public static function regexall( &$parser , $subject = '' , $pattern = '' , $separator = ', ' , $offset = 0 , $length = '' ) { |
| 343 | + // check whether limit exceeded: |
| 344 | + if( self::limitExceeded( $parser ) ) { |
| 345 | + return self::msgLimitExceeded(); |
| 346 | + } |
| 347 | + self::increaseRegexCount( $parser ); |
| 348 | + |
307 | 349 | // validate and check for wrong input: |
308 | 350 | $continue = self::validateRegexCall( $parser, $subject, $pattern, $specialFlags, false ); |
309 | 351 | if( ! $continue ) { |
310 | | - return self::invalidRegexParsingOutput( $pattern );; |
| 352 | + return self::msgInvalidRegex( $pattern );; |
311 | 353 | } |
312 | 354 | |
313 | 355 | // adjust default values: |
— | — | @@ -334,13 +376,13 @@ |
335 | 377 | return ''; |
336 | 378 | } |
337 | 379 | |
338 | | - /** |
339 | | - * Returns a value from the last performed regex match |
| 380 | + /** |
| 381 | + * Returns a value from the last performed regex match |
340 | 382 | * |
341 | | - * @index $parser Parser instance of running Parser |
342 | | - * @param $index Integer index of the last match which should be returnd or a string containing $n as indexes to be replaced |
343 | | - * @param $defaultVal Integer default value which will be returned when the result with the given index doesn't exist or is a void string |
344 | | - */ |
| 383 | + * @index $parser Parser instance of running Parser |
| 384 | + * @param $index Integer index of the last match which should be returnd or a string containing $n as indexes to be replaced |
| 385 | + * @param $defaultVal Integer default value which will be returned when the result with the given index doesn't exist or is a void string |
| 386 | + */ |
345 | 387 | public static function regex_var( &$parser, $index = 0, $defaultVal = '' ) { |
346 | 388 | // get matches from last #regex |
347 | 389 | $lastMatches = self::getLastMatches( $parser ); |
— | — | @@ -360,6 +402,13 @@ |
361 | 403 | } |
362 | 404 | } else { |
363 | 405 | // complex string is given, something like "$1, $2 and $3": |
| 406 | + |
| 407 | + // limit check, only in complex mode: |
| 408 | + if( self::limitExceeded( $parser ) ) { |
| 409 | + return self::msgLimitExceeded(); |
| 410 | + } |
| 411 | + self::increaseRegexCount( $parser ); |
| 412 | + |
364 | 413 | /* |
365 | 414 | * replace all back-references with their number increased by 1! |
366 | 415 | * this way we can also handle $0 in the right way! |
— | — | @@ -396,16 +445,16 @@ |
397 | 446 | } |
398 | 447 | return preg_replace( '%\d+%', (int)$index + 1, $full ); |
399 | 448 | } |
400 | | - |
401 | | - /** |
402 | | - * takes $str and puts a backslash in front of each character that is part of the regular expression syntax |
| 449 | + |
| 450 | + /** |
| 451 | + * takes $str and puts a backslash in front of each character that is part of the regular expression syntax |
403 | 452 | * |
404 | | - * @param $parser Parser instance of running Parser |
405 | | - * @param $str String input string to change |
406 | | - * @param $delimiter String delimiter which also will be escaped within $str (default is set to '/') |
| 453 | + * @param $parser Parser instance of running Parser |
| 454 | + * @param $str String input string to change |
| 455 | + * @param $delimiter String delimiter which also will be escaped within $str (default is set to '/') |
407 | 456 | * |
408 | | - * @return String Returns the quoted string |
409 | | - */ |
| 457 | + * @return String Returns the quoted string |
| 458 | + */ |
410 | 459 | public static function regexquote( &$parser, $str = null, $delimiter = '/' ) { |
411 | 460 | if( $str === null ) { |
412 | 461 | return ''; |
— | — | @@ -432,11 +481,26 @@ |
433 | 482 | return $str; |
434 | 483 | } |
435 | 484 | |
| 485 | + public static function onParserLimitReport( $parser, &$report ) { |
| 486 | + global $egRegexFunMaxRegexPerParse; |
| 487 | + $count = self::getLimitCount( $parser ); |
| 488 | + |
| 489 | + $report .= 'ExtRegexFun count: '; |
| 490 | + |
| 491 | + if( $egRegexFunMaxRegexPerParse !== -1 ) { |
| 492 | + $report .= "{$count}/{$egRegexFunMaxRegexPerParse}\n"; |
| 493 | + } |
| 494 | + else { |
| 495 | + $report .= "{$count}\n"; |
| 496 | + } |
| 497 | + return true; |
| 498 | + } |
436 | 499 | |
437 | | - /********************************* |
438 | | - **** HELPER - For Store of **** |
439 | | - **** regex_var within Parser **** |
440 | | - ********************************* |
| 500 | + |
| 501 | + /*********************************** |
| 502 | + **** HELPER - For store of **** |
| 503 | + **** regex stuff within Parser **** |
| 504 | + *********************************** |
441 | 505 | **** |
442 | 506 | ** |
443 | 507 | * Adding the info to each Parser object makes it invulnerable to new Parser objects being created |
— | — | @@ -454,14 +518,41 @@ |
455 | 519 | |
456 | 520 | public static function onParserClearState( &$parser ) { |
457 | 521 | //cleanup to avoid conflicts with job queue or Special:Import |
| 522 | + $parser->mExtRegexFun = array(); |
458 | 523 | self::setLastMatches( $parser, null ); |
459 | 524 | self::setLastPattern( $parser, '' ); |
460 | | - self::setLastSubject( $parser, '' ); |
| 525 | + self::setLastSubject( $parser, '' ); |
| 526 | + $parser->mExtRegexFun['counter'] = 0; |
461 | 527 | |
462 | 528 | return true; |
463 | 529 | } |
464 | 530 | |
465 | 531 | /** |
| 532 | + * Returns whether the maximum limit of regular expression has been exceeded |
| 533 | + * for the given parser objects current Parser::parse() process. |
| 534 | + * |
| 535 | + * @return boolean |
| 536 | + */ |
| 537 | + public static function limitExceeded( Parser &$parser ) { |
| 538 | + global $egRegexFunMaxRegexPerParse; |
| 539 | + return ( |
| 540 | + $egRegexFunMaxRegexPerParse !== -1 |
| 541 | + && $parser->mExtRegexFun['counter'] >= $egRegexFunMaxRegexPerParse |
| 542 | + ); |
| 543 | + } |
| 544 | + |
| 545 | + public static function getLimitCount( Parser &$parser ) { |
| 546 | + if( isset( $parser->mExtRegexFun['counter'] ) ) { |
| 547 | + return $parser->mExtRegexFun['counter']; |
| 548 | + } |
| 549 | + return 0; |
| 550 | + } |
| 551 | + |
| 552 | + private static function increaseRegexCount( Parser &$parser ) { |
| 553 | + $parser->mExtRegexFun['counter']++; |
| 554 | + } |
| 555 | + |
| 556 | + /** |
466 | 557 | * Returns the last regex matches done by #regex in the context of the same parser object. |
467 | 558 | * |
468 | 559 | * @param Parser $parser |
Index: trunk/extensions/RegexFun/RegexFun_Settings.php |
— | — | @@ -0,0 +1,44 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * File defining the settings for the 'Regex Fun' extension. |
| 6 | + * More info can be found at http://www.mediawiki.org/wiki/Extension:Regex_Fun#Configuration |
| 7 | + * |
| 8 | + * NOTICE: |
| 9 | + * ======= |
| 10 | + * Changing one of these settings can be done by copying and placing |
| 11 | + * it in LocalSettings.php, AFTER the inclusion of 'Regex Fun'. |
| 12 | + * |
| 13 | + * @file RegexFun_Settings.php |
| 14 | + * @ingroup RegexFun |
| 15 | + * @since 1.0.1 |
| 16 | + * |
| 17 | + * @author Daniel Werner |
| 18 | + */ |
| 19 | + |
| 20 | +/** |
| 21 | + * Allows to define functions which should not be available within the wiki. |
| 22 | + * |
| 23 | + * @example |
| 24 | + * # disable '#regexall' and '#regex_var' functions: |
| 25 | + * $egRegexFunDisabledFunctions = array( 'regexall', 'regex_var' ); |
| 26 | + * |
| 27 | + * @since 1.0.1 |
| 28 | + * @var array |
| 29 | + */ |
| 30 | +$egRegexFunDisabledFunctions = array(); |
| 31 | + |
| 32 | + |
| 33 | +/** |
| 34 | + * Defines the maximum regular expression executions per parser process. This |
| 35 | + * counts all executed regular expression usages by this extension. The counter |
| 36 | + * will be increased by '#regex', '#regexall' and '#regex_var' if a reference |
| 37 | + * string is given but not if only a index is requested. '#regexquote' is not |
| 38 | + * affected. When the limit is exceeded, a '#iferror' catchable error message |
| 39 | + * will be put out instead of the result of the function. |
| 40 | + * The limit can be set to -1 to disable the limit (default). |
| 41 | + * |
| 42 | + * @since 1.0.1 |
| 43 | + * @var integer |
| 44 | + */ |
| 45 | +$egRegexFunMaxRegexPerParse = -1; |
Property changes on: trunk/extensions/RegexFun/RegexFun_Settings.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 46 | + native |