Index: trunk/extensions/SpamBlacklist/SpamBlacklist.php |
— | — | @@ -3,7 +3,9 @@ |
4 | 4 | # Loader for spam blacklist feature |
5 | 5 | # Include this from LocalSettings.php |
6 | 6 | |
7 | | -if ( defined( 'MEDIAWIKI' ) ) { |
| 7 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 8 | + exit; |
| 9 | +} |
8 | 10 | |
9 | 11 | global $wgFilterCallback, $wgPreSpamFilterCallback; |
10 | 12 | global $wgSpamBlacklistFiles; |
— | — | @@ -12,101 +14,101 @@ |
13 | 15 | $wgSpamBlacklistFiles = false; |
14 | 16 | $wgSpamBlacklistSettings = array(); |
15 | 17 | |
16 | | -if ( $wgFilterCallback ) { |
17 | | - $wgPreSpamFilterCallback = $wgFilterCallback; |
| 18 | +$wgPreSpamFilterCallback = false; |
| 19 | + |
| 20 | +if ( defined( 'MW_SUPPORTS_EDITFILTERMERGED' ) ) { |
| 21 | + $wgHooks['EditFilterMerged'][] = 'wfSpamBlacklistFilterMerged'; |
18 | 22 | } else { |
19 | | - $wgPreSpamFilterCallback = false; |
| 23 | + if ( $wgFilterCallback ) { |
| 24 | + $wgPreSpamFilterCallback = $wgFilterCallback; |
| 25 | + } |
| 26 | + $wgFilterCallback = 'wfSpamBlacklistFilter'; |
20 | 27 | } |
21 | 28 | |
22 | | -$wgFilterCallback = 'wfSpamBlacklistLoader'; |
23 | 29 | $wgExtensionCredits['other'][] = array( |
24 | 30 | 'name' => 'SpamBlacklist', |
25 | 31 | 'author' => 'Tim Starling', |
26 | 32 | 'url' => 'http://www.mediawiki.org/wiki/Extension:SpamBlacklist', |
27 | | - 'description' => 'Regex based anti spam tool', |
| 33 | + 'description' => 'Regex-based anti-spam tool', |
28 | 34 | ); |
29 | 35 | |
30 | | -$wgExtensionFunctions[] = 'wfSpamBlacklistMessageLoader'; |
31 | | - |
32 | 36 | $wgHooks['EditFilter'][] = 'wfSpamBlacklistValidate'; |
33 | | -$wgHooks['ArticleSaveComplete'][] = 'wfSpamBlacklistClearCache'; |
| 37 | +$wgHooks['ArticleSaveComplete'][] = 'wfSpamBlacklistArticleSave'; |
34 | 38 | |
35 | | -function wfSpamBlacklistMessageLoader() { |
| 39 | +/** |
| 40 | + * Load SpamBlacklist.i18n.php |
| 41 | + */ |
| 42 | +function wfSpamBlacklistLoadMessages() { |
36 | 43 | global $wgMessageCache; |
37 | | - require_once( 'SpamBlacklist.i18n.php' ); |
38 | | - foreach( efSpamBlacklistMessages() as $lang => $messages ) { |
39 | | - $wgMessageCache->addMessages( $messages, $lang ); |
| 44 | + static $done = false; |
| 45 | + if ( $done ) { |
| 46 | + return; |
40 | 47 | } |
41 | | -} |
| 48 | + $done = true; |
42 | 49 | |
43 | | -function wfSpamBlacklistLoader( &$title, $text, $section ) { |
44 | | - static $spamObj = false; |
45 | | - |
46 | | - if ( $spamObj === false ) { |
47 | | - $spamObj = wfSpamBlacklistObject(); |
| 50 | + require( 'SpamBlacklist.i18n.php' ); |
| 51 | + if ( is_callable( array( $wgMessageCache, 'addMessagesByLang' ) ) ) { |
| 52 | + $wgMessageCache->addMessagesByLang( $messages ); |
| 53 | + } else { |
| 54 | + foreach( $messages as $lang => $langMessages ) { |
| 55 | + $wgMessageCache->addMessages( $langMessages, $lang ); |
| 56 | + } |
48 | 57 | } |
49 | | - |
50 | | - return $spamObj->filter( $title, $text, $section ); |
51 | 58 | } |
52 | 59 | |
| 60 | +/** |
| 61 | + * Get an instance of SpamBlacklist and do some first-call initialisation. |
| 62 | + * All actual functionality is implemented in that object |
| 63 | + */ |
53 | 64 | function wfSpamBlacklistObject() { |
54 | | - require_once( "SpamBlacklist_body.php" ); |
55 | 65 | global $wgSpamBlacklistFiles, $wgSpamBlacklistSettings, $wgPreSpamFilterCallback; |
56 | | - $spamObj = new SpamBlacklist( $wgSpamBlacklistSettings ); |
57 | | - if( $wgSpamBlacklistFiles ) { |
58 | | - $spamObj->files = $wgSpamBlacklistFiles; |
| 66 | + static $spamObj; |
| 67 | + if ( !$spamObj ) { |
| 68 | + require_once( "SpamBlacklist_body.php" ); |
| 69 | + $spamObj = new SpamBlacklist( $wgSpamBlacklistSettings ); |
| 70 | + if( $wgSpamBlacklistFiles ) { |
| 71 | + $spamObj->files = $wgSpamBlacklistFiles; |
| 72 | + } |
| 73 | + $spamObj->previousFilter = $wgPreSpamFilterCallback; |
| 74 | + wfSpamBlacklistLoadMessages(); |
59 | 75 | } |
60 | | - $spamObj->previousFilter = $wgPreSpamFilterCallback; |
61 | 76 | return $spamObj; |
62 | 77 | } |
63 | 78 | |
64 | 79 | /** |
| 80 | + * Hook function for $wgFilterCallback |
| 81 | + */ |
| 82 | +function wfSpamBlacklistFilter( &$title, $text, $section ) { |
| 83 | + $spamObj = wfSpamBlacklistObject(); |
| 84 | + return $spamObj->filter( $title, $text, $section ); |
| 85 | +} |
| 86 | + |
| 87 | +/** |
| 88 | + * Hook function for EditFilterMerged, replaces wfSpamBlacklistFilter |
| 89 | + */ |
| 90 | +function wfSpamBlacklistFilterMerged( $editPage, $text ) { |
| 91 | + $spamObj = wfSpamBlacklistObject(); |
| 92 | + $ret = $spamObj->filter( $editPage->mArticle->getTitle(), $text, '', $editPage ); |
| 93 | + // Return convention for hooks is the inverse of $wgFilterCallback |
| 94 | + return !$ret; |
| 95 | +} |
| 96 | + |
| 97 | +/** |
| 98 | + * Hook function for EditFilter |
65 | 99 | * Confirm that a local blacklist page being saved is valid, |
66 | 100 | * and toss back a warning to the user if it isn't. |
67 | 101 | */ |
68 | 102 | function wfSpamBlacklistValidate( $editPage, $text, $section, &$hookError ) { |
69 | | - $thisPageName = $editPage->mTitle->getPrefixedDBkey(); |
70 | | - |
71 | 103 | $spamObj = wfSpamBlacklistObject(); |
72 | | - if( !$spamObj->isLocalSource( $editPage->mTitle ) ) { |
73 | | - wfDebugLog( 'SpamBlacklist', "Spam blacklist validator: [[$thisPageName]] not a local blacklist\n" ); |
74 | | - return true; |
75 | | - } |
76 | | - |
77 | | - $lines = explode( "\n", $text ); |
78 | | - |
79 | | - $badLines = SpamRegexBatch::getBadLines( $lines ); |
80 | | - if( $badLines ) { |
81 | | - wfDebugLog( 'SpamBlacklist', "Spam blacklist validator: [[$thisPageName]] given invalid input lines: " . |
82 | | - implode( ', ', $badLines ) . "\n" ); |
83 | | - |
84 | | - $badList = "*<tt>" . |
85 | | - implode( "</tt>\n*<tt>", |
86 | | - array_map( 'wfEscapeWikiText', $badLines ) ) . |
87 | | - "</tt>\n"; |
88 | | - $hookError = |
89 | | - "<div class='errorbox'>" . |
90 | | - wfMsgExt( 'spam-invalid-lines', array( 'parsemag' ), count( $badLines ) ) . |
91 | | - $badList . |
92 | | - "</div>\n" . |
93 | | - "<br clear='all' />\n"; |
94 | | - return true; |
95 | | - } else { |
96 | | - wfDebugLog( 'SpamBlacklist', "Spam blacklist validator: [[$thisPageName]] ok or empty blacklist\n" ); |
97 | | - return true; |
98 | | - } |
| 104 | + return $spamObj->validate( $editPage, $text, $section, &$hookError ); |
99 | 105 | } |
100 | 106 | |
101 | 107 | /** |
| 108 | + * Hook function for ArticleSaveComplete |
102 | 109 | * Clear local spam blacklist caches on page save. |
103 | 110 | */ |
104 | | -function wfSpamBlacklistClearCache( &$article, &$user, $text, $summary, $isminor, $iswatch, $section ) { |
| 111 | +function wfSpamBlacklistArticleSave( &$article, &$user, $text, $summary, $isminor, $iswatch, $section ) { |
105 | 112 | $spamObj = wfSpamBlacklistObject(); |
106 | | - if( $spamObj->isLocalSource( $article->getTitle() ) ) { |
107 | | - $spamObj->clearCache(); |
108 | | - } |
109 | | - return true; |
| 113 | + return $spamObj->onArticleSave( &$article, &$user, $text, $summary, $isminor, $iswatch, $section ); |
110 | 114 | } |
111 | 115 | |
112 | | - |
113 | | -} # End invocation guard |
Index: trunk/extensions/SpamBlacklist/SpamBlacklist_body.php |
— | — | @@ -1,6 +1,8 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -if ( defined( 'MEDIAWIKI' ) ) { |
| 4 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 5 | + exit; |
| 6 | +} |
5 | 7 | |
6 | 8 | class SpamBlacklist { |
7 | 9 | var $regexes = false; |
— | — | @@ -11,8 +13,6 @@ |
12 | 14 | var $warningChance = 100; |
13 | 15 | |
14 | 16 | function SpamBlacklist( $settings = array() ) { |
15 | | - global $IP; |
16 | | - |
17 | 17 | foreach ( $settings as $name => $value ) { |
18 | 18 | $this->$name = $value; |
19 | 19 | } |
— | — | @@ -180,7 +180,15 @@ |
181 | 181 | return SpamRegexBatch::regexesFromMessage( 'spam-whitelist' ); |
182 | 182 | } |
183 | 183 | |
184 | | - function filter( &$title, $text, $section ) { |
| 184 | + /** |
| 185 | + * @param Title $title |
| 186 | + * @param string $text Text of section, or entire text if $editPage!=false |
| 187 | + * @param string $section Section number or name |
| 188 | + * @param EditPage $editPage EditPage if EditFilterMerged was called, false otherwise |
| 189 | + * @return True if the edit should not be allowed, false otherwise |
| 190 | + * If the return value is true, an error will have been sent to $wgOut |
| 191 | + */ |
| 192 | + function filter( &$title, $text, $section, $editPage = false ) { |
185 | 193 | global $wgArticle, $wgVersion, $wgOut, $wgParser, $wgUser; |
186 | 194 | |
187 | 195 | $fname = 'wfSpamBlacklistFilter'; |
— | — | @@ -205,9 +213,14 @@ |
206 | 214 | if ( count( $blacklists ) ) { |
207 | 215 | # Run parser to strip SGML comments and such out of the markup |
208 | 216 | # This was being used to circumvent the filter (see bug 5185) |
209 | | - $options = new ParserOptions(); |
210 | | - $text = $wgParser->preSaveTransform( $text, $title, $wgUser, $options ); |
211 | | - $out = $wgParser->parse( $text, $title, $options ); |
| 217 | + if ( $editPage ) { |
| 218 | + $editInfo = $editPage->mArticle->prepareTextForEdit( $text ); |
| 219 | + $out = $editInfo->output; |
| 220 | + } else { |
| 221 | + $options = new ParserOptions(); |
| 222 | + $text = $wgParser->preSaveTransform( $text, $title, $wgUser, $options ); |
| 223 | + $out = $wgParser->parse( $text, $title, $options ); |
| 224 | + } |
212 | 225 | $links = implode( "\n", array_keys( $out->getExternalLinks() ) ); |
213 | 226 | |
214 | 227 | # Strip whitelisted URLs from the match |
— | — | @@ -235,7 +248,11 @@ |
236 | 249 | wfRestoreWarnings(); |
237 | 250 | if( $check ) { |
238 | 251 | wfDebugLog( 'SpamBlacklist', "Match!\n" ); |
239 | | - EditPage::spamPage( $matches[0] ); |
| 252 | + if ( $editPage ) { |
| 253 | + $editPage->spamPage( $matches[0] ); |
| 254 | + } else { |
| 255 | + EditPage::spamPage( $matches[0] ); |
| 256 | + } |
240 | 257 | $retVal = true; |
241 | 258 | break; |
242 | 259 | } |
— | — | @@ -294,6 +311,50 @@ |
295 | 312 | wfRestoreWarnings(); |
296 | 313 | return $text; |
297 | 314 | } |
| 315 | + |
| 316 | + /** |
| 317 | + * Confirm that a local blacklist page being saved is valid, |
| 318 | + * and toss back a warning to the user if it isn't. |
| 319 | + * This is an EditFilter hook. |
| 320 | + */ |
| 321 | + function validate( $editPage, $text, $section, &$hookError ) { |
| 322 | + $thisPageName = $editPage->mTitle->getPrefixedDBkey(); |
| 323 | + |
| 324 | + if( !$this->isLocalSource( $editPage->mTitle ) ) { |
| 325 | + wfDebugLog( 'SpamBlacklist', "Spam blacklist validator: [[$thisPageName]] not a local blacklist\n" ); |
| 326 | + return true; |
| 327 | + } |
| 328 | + |
| 329 | + $lines = explode( "\n", $text ); |
| 330 | + |
| 331 | + $badLines = SpamRegexBatch::getBadLines( $lines ); |
| 332 | + if( $badLines ) { |
| 333 | + wfDebugLog( 'SpamBlacklist', "Spam blacklist validator: [[$thisPageName]] given invalid input lines: " . |
| 334 | + implode( ', ', $badLines ) . "\n" ); |
| 335 | + |
| 336 | + $badList = "*<tt>" . |
| 337 | + implode( "</tt>\n*<tt>", |
| 338 | + array_map( 'wfEscapeWikiText', $badLines ) ) . |
| 339 | + "</tt>\n"; |
| 340 | + $hookError = |
| 341 | + "<div class='errorbox'>" . |
| 342 | + wfMsgExt( 'spam-invalid-lines', array( 'parsemag' ), count( $badLines ) ) . |
| 343 | + $badList . |
| 344 | + "</div>\n" . |
| 345 | + "<br clear='all' />\n"; |
| 346 | + return true; |
| 347 | + } else { |
| 348 | + wfDebugLog( 'SpamBlacklist', "Spam blacklist validator: [[$thisPageName]] ok or empty blacklist\n" ); |
| 349 | + return true; |
| 350 | + } |
| 351 | + } |
| 352 | + |
| 353 | + function onArticleSave( &$article, &$user, $text, $summary, $isminor, $iswatch, $section ) { |
| 354 | + if( $this->isLocalSource( $article->getTitle() ) ) { |
| 355 | + $this->clearCache(); |
| 356 | + } |
| 357 | + return true; |
| 358 | + } |
298 | 359 | } |
299 | 360 | |
300 | 361 | |
— | — | @@ -450,5 +511,3 @@ |
451 | 512 | } |
452 | 513 | } |
453 | 514 | |
454 | | -} # End invocation guard |
455 | | - |
Index: trunk/extensions/SpamBlacklist/SpamBlacklist.i18n.php |
— | — | @@ -3,16 +3,10 @@ |
4 | 4 | * Internationalisation file for SpamBlacklist extension. |
5 | 5 | * |
6 | 6 | * @addtogroup Extensions |
7 | | -*/ |
8 | | - |
9 | | -/** |
10 | | - * Prepare extension messages |
11 | | - * |
12 | | - * @return array |
13 | 7 | */ |
14 | | -function efSpamBlacklistMessages() { |
15 | | - $messages = array( |
16 | 8 | |
| 9 | +$messages = array( |
| 10 | + |
17 | 11 | 'en' => array( |
18 | 12 | 'spam-blacklist' => ' |
19 | 13 | # External URLs matching this list will be blocked when added to a page. |
— | — | @@ -351,14 +345,11 @@ |
352 | 346 | "請在保存這頁前先將{{PLURAL:$1|它|它們}}修正:\n", |
353 | 347 | ), |
354 | 348 | |
355 | | - ); |
| 349 | +); |
356 | 350 | |
357 | | - $messages['zh'] = $messages['zh-hans']; |
358 | | - $messages['zh-cn'] = $messages['zh-hans']; |
359 | | - $messages['zh-hk'] = $messages['zh-hant']; |
360 | | - $messages['zh-sg'] = $messages['zh-hans']; |
361 | | - $messages['zh-tw'] = $messages['zh-hant']; |
362 | | - $messages['zh-yue'] = $messages['yue']; |
363 | | - |
364 | | -return $messages; |
365 | | -} |
| 351 | +$messages['zh'] = $messages['zh-hans']; |
| 352 | +$messages['zh-cn'] = $messages['zh-hans']; |
| 353 | +$messages['zh-hk'] = $messages['zh-hant']; |
| 354 | +$messages['zh-sg'] = $messages['zh-hans']; |
| 355 | +$messages['zh-tw'] = $messages['zh-hant']; |
| 356 | +$messages['zh-yue'] = $messages['yue']; |