Index: trunk/extensions/ParserFunctions/ParserFunctions.php |
— | — | @@ -16,10 +16,7 @@ |
17 | 17 | |
18 | 18 | $wgExtensionMessagesFiles['ParserFunctions'] = dirname(__FILE__) . '/ParserFunctions.i18n.php'; |
19 | 19 | $wgHooks['LanguageGetMagic'][] = 'wfParserFunctionsLanguageGetMagic'; |
20 | | -$wgHooks['ParserLimitReport'][] = 'wfParserFunctionsLimitReport'; |
21 | 20 | |
22 | | -$wgMaxIfExistCount = 100; |
23 | | - |
24 | 21 | class ExtParserFunctions { |
25 | 22 | var $mExprParser; |
26 | 23 | var $mTimeCache = array(); |
— | — | @@ -55,7 +52,6 @@ |
56 | 53 | |
57 | 54 | function clearState(&$parser) { |
58 | 55 | $this->mTimeChars = 0; |
59 | | - $parser->pf_ifexist_count = 0; |
60 | 56 | $parser->pf_ifexist_breakdown = array(); |
61 | 57 | return true; |
62 | 58 | } |
— | — | @@ -315,8 +311,8 @@ |
316 | 312 | |
317 | 313 | function incrementIfexistCount( $parser, $frame ) { |
318 | 314 | // Don't let this be called more than a certain number of times. It tends to make the database explode. |
319 | | - global $wgMaxIfExistCount; |
320 | | - $parser->pf_ifexist_count++; |
| 315 | + global $wgExpensiveParserFunctionLimit; |
| 316 | + $parser->mExpensiveFunctionCount++; |
321 | 317 | if ( $frame ) { |
322 | 318 | $pdbk = $frame->getPDBK( 1 ); |
323 | 319 | if ( !isset( $parser->pf_ifexist_breakdown[$pdbk] ) ) { |
— | — | @@ -324,7 +320,7 @@ |
325 | 321 | } |
326 | 322 | $parser->pf_ifexist_breakdown[$pdbk] ++; |
327 | 323 | } |
328 | | - return $parser->pf_ifexist_count <= $wgMaxIfExistCount; |
| 324 | + return $parser->mExpensiveFunctionCount <= $wgExpensiveParserFunctionLimit; |
329 | 325 | } |
330 | 326 | |
331 | 327 | function ifexist( &$parser, $title = '', $then = '', $else = '' ) { |
— | — | @@ -357,15 +353,14 @@ |
358 | 354 | } else { |
359 | 355 | $pdbk = $title->getPrefixedDBkey(); |
360 | 356 | $lc = LinkCache::singleton(); |
| 357 | + if ( !$this->incrementIfexistCount( $parser, $frame ) ) { |
| 358 | + return $else; |
| 359 | + } |
361 | 360 | if ( $lc->getGoodLinkID( $pdbk ) ) { |
362 | 361 | return $then; |
363 | 362 | } elseif ( $lc->isBadLink( $pdbk ) ) { |
364 | 363 | return $else; |
365 | 364 | } |
366 | | - if ( !$this->incrementIfexistCount( $parser, $frame ) ) { |
367 | | - return $else; |
368 | | - } |
369 | | - |
370 | 365 | $id = $title->getArticleID(); |
371 | 366 | $parser->mOutput->addLink( $title, $id ); |
372 | 367 | if ( $id ) { |
— | — | @@ -476,22 +471,6 @@ |
477 | 472 | return $title; |
478 | 473 | } |
479 | 474 | } |
480 | | - |
481 | | - function afterTidy( &$parser, &$text ) { |
482 | | - global $wgMaxIfExistCount; |
483 | | - if ( $parser->pf_ifexist_count > $wgMaxIfExistCount ) { |
484 | | - if ( is_callable( array( $parser->mOutput, 'addWarning' ) ) ) { |
485 | | - wfLoadExtensionMessages( 'ParserFunctions' ); |
486 | | - $warning = wfMsg( 'pfunc_ifexist_warning', $parser->pf_ifexist_count, $wgMaxIfExistCount ); |
487 | | - $parser->mOutput->addWarning( $warning ); |
488 | | - $cat = Title::makeTitleSafe( NS_CATEGORY, wfMsgForContent( 'pfunc_max_ifexist_category' ) ); |
489 | | - if ( $cat ) { |
490 | | - $parser->mOutput->addCategory( $cat->getDBkey(), $parser->getDefaultSort() ); |
491 | | - } |
492 | | - } |
493 | | - } |
494 | | - return true; |
495 | | - } |
496 | 475 | } |
497 | 476 | |
498 | 477 | function wfSetupParserFunctions() { |
— | — | @@ -510,7 +489,6 @@ |
511 | 490 | } |
512 | 491 | |
513 | 492 | $wgHooks['ParserClearState'][] = array( &$wgExtParserFunctions, 'clearState' ); |
514 | | - $wgHooks['ParserAfterTidy'][] = array( &$wgExtParserFunctions, 'afterTidy' ); |
515 | 493 | } |
516 | 494 | |
517 | 495 | function wfParserFunctionsLanguageGetMagic( &$magicWords, $langCode ) { |
— | — | @@ -520,11 +498,3 @@ |
521 | 499 | return true; |
522 | 500 | } |
523 | 501 | |
524 | | -function wfParserFunctionsLimitReport( $parser, &$report ) { |
525 | | - global $wgMaxIfExistCount; |
526 | | - if ( isset( $parser->pf_ifexist_count ) ) { |
527 | | - $report .= "#ifexist count: {$parser->pf_ifexist_count}/$wgMaxIfExistCount\n"; |
528 | | - } |
529 | | - return true; |
530 | | -} |
531 | | - |
Index: trunk/phase3/includes/Parser.php |
— | — | @@ -102,6 +102,7 @@ |
103 | 103 | var $mIncludeSizes, $mPPNodeCount, $mDefaultSort; |
104 | 104 | var $mTplExpandCache; // empty-frame expansion cache |
105 | 105 | var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores; |
| 106 | + var $mExpensiveFunctionCount; // number of expensive parser function calls |
106 | 107 | |
107 | 108 | # Temporary |
108 | 109 | # These are variables reset at least once per parse regardless of $clearState |
— | — | @@ -217,6 +218,7 @@ |
218 | 219 | $this->mDefaultSort = false; |
219 | 220 | $this->mHeadings = array(); |
220 | 221 | $this->mDoubleUnderscores = array(); |
| 222 | + $this->mExpensiveFunctionCount = 0; |
221 | 223 | |
222 | 224 | # Fix cloning |
223 | 225 | if ( isset( $this->mPreprocessor ) && $this->mPreprocessor->parser !== $this ) { |
— | — | @@ -390,17 +392,31 @@ |
391 | 393 | array_values( $tidyregs ), |
392 | 394 | $text ); |
393 | 395 | } |
| 396 | + global $wgExpensiveParserFunctionLimit; |
| 397 | + if ( $this->mExpensiveFunctionCount > $wgExpensiveParserFunctionLimit ) { |
| 398 | + if ( is_callable( array( $this->mOutput, 'addWarning' ) ) ) { |
| 399 | + $warning = wfMsg( 'expensive-parserfunction-warning', $this->mExpensiveFunctionCount, $wgExpensiveParserFunctionLimit ); |
| 400 | + $this->mOutput->addWarning( $warning ); |
| 401 | + $cat = Title::makeTitleSafe( NS_CATEGORY, wfMsgForContent( 'expensive-parserfunction-category' ) ); |
| 402 | + if ( $cat ) { |
| 403 | + $this->mOutput->addCategory( $cat->getDBkey(), $this->getDefaultSort() ); |
| 404 | + } |
| 405 | + } |
| 406 | + } |
394 | 407 | |
395 | 408 | wfRunHooks( 'ParserAfterTidy', array( &$this, &$text ) ); |
396 | 409 | |
397 | 410 | # Information on include size limits, for the benefit of users who try to skirt them |
398 | 411 | if ( $this->mOptions->getEnableLimitReport() ) { |
| 412 | + global $wgExpensiveParserFunctionLimit; |
399 | 413 | $max = $this->mOptions->getMaxIncludeSize(); |
| 414 | + $PFreport = "Expensive parser function count: {$this->mExpensiveFunctionCount}/$wgExpensiveParserFunctionLimit\n"; |
400 | 415 | $limitReport = |
401 | 416 | "NewPP limit report\n" . |
402 | 417 | "Preprocessor node count: {$this->mPPNodeCount}/{$this->mOptions->mMaxPPNodeCount}\n" . |
403 | 418 | "Post-expand include size: {$this->mIncludeSizes['post-expand']}/$max bytes\n" . |
404 | | - "Template argument size: {$this->mIncludeSizes['arg']}/$max bytes\n"; |
| 419 | + "Template argument size: {$this->mIncludeSizes['arg']}/$max bytes\n". |
| 420 | + $PFreport; |
405 | 421 | wfRunHooks( 'ParserLimitReport', array( $this, &$limitReport ) ); |
406 | 422 | $text .= "\n<!-- \n$limitReport-->\n"; |
407 | 423 | } |
Index: trunk/phase3/includes/MagicWord.php |
— | — | @@ -102,6 +102,7 @@ |
103 | 103 | 'pagesinnamespace', |
104 | 104 | 'numberofadmins', |
105 | 105 | 'defaultsort', |
| 106 | + 'pagesincategory', |
106 | 107 | ); |
107 | 108 | |
108 | 109 | /* Array of caching hints for ParserCache */ |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -3011,3 +3011,9 @@ |
3012 | 3012 | * Special:Whatlinkshere/RedirectDestination |
3013 | 3013 | */ |
3014 | 3014 | $wgMaxRedirectLinksRetrieved = 500; |
| 3015 | + |
| 3016 | +/** |
| 3017 | +* Maximum number of calls to expensive parser functions |
| 3018 | +* such as PAGESINCATEGORY. |
| 3019 | +*/ |
| 3020 | +$wgExpensiveParserFunctionLimit = 100; |
Index: trunk/phase3/includes/CoreParserFunctions.php |
— | — | @@ -41,6 +41,7 @@ |
42 | 42 | $parser->setFunctionHook( 'special', array( __CLASS__, 'special' ) ); |
43 | 43 | $parser->setFunctionHook( 'defaultsort', array( __CLASS__, 'defaultsort' ), SFH_NO_HASH ); |
44 | 44 | $parser->setFunctionHook( 'filepath', array( __CLASS__, 'filepath' ), SFH_NO_HASH ); |
| 45 | + $parser->setFunctionHook( 'pagesincategory', array( __CLASS__, 'pagesincategory' ), SFH_NO_HASH ); |
45 | 46 | $parser->setFunctionHook( 'tag', array( __CLASS__, 'tagObj' ), SFH_OBJECT_ARGS ); |
46 | 47 | |
47 | 48 | if ( $wgAllowDisplayTitle ) { |
— | — | @@ -214,6 +215,23 @@ |
215 | 216 | static function pagesinnamespace( $parser, $namespace = 0, $raw = null ) { |
216 | 217 | return self::formatRaw( SiteStats::pagesInNs( intval( $namespace ) ), $raw ); |
217 | 218 | } |
| 219 | + |
| 220 | + static function pagesincategory( $parser, $category = '', $raw = null ) { |
| 221 | + global $wgExpensiveParserFunctionLimit; |
| 222 | + if ($category == '') { |
| 223 | + return 0; |
| 224 | + } |
| 225 | + $parser->mExpensiveFunctionCount++; |
| 226 | + if ($parser->mExpensiveFunctionCount <= $wgExpensiveParserFunctionLimit) { |
| 227 | + $category = Category::newFromName($category); |
| 228 | + $count = $category->getPageCount(); |
| 229 | + if ( !$count ) { |
| 230 | + $count = 0; |
| 231 | + } |
| 232 | + return self::formatRaw( $count, $raw ); |
| 233 | + } |
| 234 | + return 0; |
| 235 | + } |
218 | 236 | |
219 | 237 | static function language( $parser, $arg = '' ) { |
220 | 238 | global $wgContLang; |
Index: trunk/phase3/languages/messages/MessagesEn.php |
— | — | @@ -338,6 +338,7 @@ |
339 | 339 | 'filepath' => array( 0, 'FILEPATH:' ), |
340 | 340 | 'tag' => array( 0, 'tag' ), |
341 | 341 | 'hiddencat' => array( 1, '__HIDDENCAT__' ), |
| 342 | + 'pagesincategory' => array( 1, 'PAGESINCATEGORY', 'PAGESINCAT' ), |
342 | 343 | ); |
343 | 344 | |
344 | 345 | /** |
— | — | @@ -1128,7 +1129,11 @@ |
1129 | 1130 | |
1130 | 1131 | You should consider whether it is appropriate to continue editing this page. |
1131 | 1132 | The deletion log for this page is provided here for convenience:", |
| 1133 | +'expensive-parserfunction-warning' => 'Warning: This page contains too many expensive parser function calls. |
1132 | 1134 | |
| 1135 | +It should have less than $2, there are now $1.', |
| 1136 | +'expensive-parserfunction-category' => 'Pages with too many expensive parser function calls', |
| 1137 | + |
1133 | 1138 | # "Undo" feature |
1134 | 1139 | 'undo-success' => 'The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.', |
1135 | 1140 | 'undo-failure' => 'The edit could not be undone due to conflicting intermediate edits.', |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -65,7 +65,9 @@ |
66 | 66 | * Redesign of Special:Userrights |
67 | 67 | * Make rev_deleted log entries more intelligible. |
68 | 68 | * Logs are grouped under date headings similar to enhanced changes list |
| 69 | +* (6943) Added PAGESINCATEGORY: magic word |
69 | 70 | |
| 71 | + |
70 | 72 | === Bug fixes in 1.13 === |
71 | 73 | |
72 | 74 | * (bug 10677) Add link to the file description page on the shared repository |