Index: trunk/extensions/ConfirmEdit/MathCaptcha.php |
— | — | @@ -10,48 +10,9 @@ |
11 | 11 | * @licence GNU General Public Licence 2.0 |
12 | 12 | */ |
13 | 13 | |
14 | | -if( defined( 'MEDIAWIKI' ) ) { |
15 | | - |
16 | | - class MathCaptcha extends SimpleCaptcha { |
17 | | - |
18 | | - /** Validate a captcha response */ |
19 | | - function keyMatch( $req, $info ) { |
20 | | - return (int)$req->getVal( 'wpCaptchaAnswer' ) == (int)$info['answer']; |
21 | | - } |
22 | | - |
23 | | - /** Produce a nice little form */ |
24 | | - function getForm() { |
25 | | - list( $sum, $answer ) = $this->pickSum(); |
26 | | - $index = $this->storeCaptcha( array( 'answer' => $answer ) ); |
27 | | - |
28 | | - $form = '<table><tr><td>' . $this->fetchMath( $sum ) . '</td>'; |
29 | | - $form .= '<td>' . wfInput( 'wpCaptchaAnswer', false, false, array( 'tabindex' => '1' ) ) . '</td></tr></table>'; |
30 | | - $form .= wfHidden( 'wpCaptchaId', $index ); |
31 | | - return $form; |
32 | | - } |
33 | | - |
34 | | - /** Pick a random sum */ |
35 | | - function pickSum() { |
36 | | - $a = mt_rand( 0, 100 ); |
37 | | - $b = mt_rand( 0, 10 ); |
38 | | - $op = mt_rand( 0, 1 ) ? '+' : '-'; |
39 | | - $sum = "{$a} {$op} {$b} = "; |
40 | | - $ans = $op == '+' ? ( $a + $b ) : ( $a - $b ); |
41 | | - return array( $sum, $ans ); |
42 | | - } |
43 | | - |
44 | | - /** Fetch the math */ |
45 | | - function fetchMath( $sum ) { |
46 | | - $math = new MathRenderer( $sum ); |
47 | | - $math->setOutputMode( MW_MATH_PNG ); |
48 | | - $html = $math->render(); |
49 | | - return preg_replace( '/alt=".*"/', '', $html ); |
50 | | - } |
51 | | - |
52 | | - } |
53 | | - |
54 | | -} else { |
| 14 | +if( !defined( 'MEDIAWIKI' ) ) { |
55 | 15 | echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" ); |
56 | 16 | die( 1 ); |
57 | 17 | } |
| 18 | +$wgAutoloadClasses['MathCaptcha'] = dirname( __FILE__ ) . '/MathCaptcha.class.php'; |
58 | 19 | |
Index: trunk/extensions/ConfirmEdit/ConfirmEdit_body.php |
— | — | @@ -0,0 +1,670 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class ConfirmEditHooks { |
| 5 | + static function getInstance() { |
| 6 | + global $wgCaptcha, $wgCaptchaClass, $wgExtensionMessagesFiles; |
| 7 | + static $done = false; |
| 8 | + if ( !$done ) { |
| 9 | + $done = true; |
| 10 | + wfLoadExtensionMessages( 'ConfirmEdit' ); |
| 11 | + if ( isset( $wgExtensionMessagesFiles[$wgCaptchaClass] ) ) { |
| 12 | + wfLoadExtensionMessages( $wgCaptchaClass ); |
| 13 | + } |
| 14 | + $wgCaptcha = new $wgCaptchaClass; |
| 15 | + } |
| 16 | + return $wgCaptcha; |
| 17 | + } |
| 18 | + |
| 19 | + static function confirmEdit( &$editPage, $newtext, $section ) { |
| 20 | + return self::getInstance()->confirmEdit( $editPage, $newtext, $section ); |
| 21 | + } |
| 22 | + |
| 23 | + static function confirmEditMerged( &$editPage, $newtext ) { |
| 24 | + return self::getInstance()->confirmEditMerged( $editPage, $newtext ); |
| 25 | + } |
| 26 | + |
| 27 | + static function injectUserCreate( &$template ) { |
| 28 | + return self::getInstance()->injectUserCreate( $template ); |
| 29 | + } |
| 30 | + |
| 31 | + static function confirmUserCreate( $u, &$message ) { |
| 32 | + return self::getInstance()->confirmUserCreate( $u, $message ); |
| 33 | + } |
| 34 | + |
| 35 | + static function triggerUserLogin( $user, $password, $retval ) { |
| 36 | + return self::getInstance()->triggerUserLogin( $user, $password, $retval ); |
| 37 | + } |
| 38 | + |
| 39 | + static function injectUserLogin( &$template ) { |
| 40 | + return self::getInstance()->injectUserLogin( $template ); |
| 41 | + } |
| 42 | + |
| 43 | + static function confirmUserLogin( $u, $pass, &$retval ) { |
| 44 | + return self::getInstance()->confirmUserLogin( $u, $pass, $retval ); |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +class CaptchaSpecialPage extends SpecialPage { |
| 49 | + function execute( $par ) { |
| 50 | + $this->setHeaders(); |
| 51 | + $instance = ConfirmEditHooks::getInstance(); |
| 52 | + switch( $par ) { |
| 53 | + case "image": |
| 54 | + return $instance->showImage(); |
| 55 | + case "help": |
| 56 | + default: |
| 57 | + return $instance->showHelp(); |
| 58 | + } |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | + |
| 63 | +class SimpleCaptcha { |
| 64 | + function SimpleCaptcha() { |
| 65 | + global $wgCaptchaStorageClass; |
| 66 | + $this->storage = new $wgCaptchaStorageClass; |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * Insert a captcha prompt into the edit form. |
| 71 | + * This sample implementation generates a simple arithmetic operation; |
| 72 | + * it would be easy to defeat by machine. |
| 73 | + * |
| 74 | + * Override this! |
| 75 | + * |
| 76 | + * @return string HTML |
| 77 | + */ |
| 78 | + function getForm() { |
| 79 | + $a = mt_rand(0, 100); |
| 80 | + $b = mt_rand(0, 10); |
| 81 | + $op = mt_rand(0, 1) ? '+' : '-'; |
| 82 | + |
| 83 | + $test = "$a $op $b"; |
| 84 | + $answer = ($op == '+') ? ($a + $b) : ($a - $b); |
| 85 | + |
| 86 | + $index = $this->storeCaptcha( array( 'answer' => $answer ) ); |
| 87 | + |
| 88 | + return "<p><label for=\"wpCaptchaWord\">$test</label> = " . |
| 89 | + wfElement( 'input', array( |
| 90 | + 'name' => 'wpCaptchaWord', |
| 91 | + 'id' => 'wpCaptchaWord', |
| 92 | + 'tabindex' => 1 ) ) . // tab in before the edit textarea |
| 93 | + "</p>\n" . |
| 94 | + wfElement( 'input', array( |
| 95 | + 'type' => 'hidden', |
| 96 | + 'name' => 'wpCaptchaId', |
| 97 | + 'id' => 'wpCaptchaId', |
| 98 | + 'value' => $index ) ); |
| 99 | + } |
| 100 | + |
| 101 | + /** |
| 102 | + * Insert the captcha prompt into an edit form. |
| 103 | + * @param OutputPage $out |
| 104 | + */ |
| 105 | + function editCallback( &$out ) { |
| 106 | + $out->addWikiText( $this->getMessage( $this->action ) ); |
| 107 | + $out->addHTML( $this->getForm() ); |
| 108 | + } |
| 109 | + |
| 110 | + /** |
| 111 | + * Show a message asking the user to enter a captcha on edit |
| 112 | + * The result will be treated as wiki text |
| 113 | + * |
| 114 | + * @param $action Action being performed |
| 115 | + * @return string |
| 116 | + */ |
| 117 | + function getMessage( $action ) { |
| 118 | + $name = 'captcha-' . $action; |
| 119 | + $text = wfMsg( $name ); |
| 120 | + # Obtain a more tailored message, if possible, otherwise, fall back to |
| 121 | + # the default for edits |
| 122 | + return wfEmptyMsg( $name, $text ) ? wfMsg( 'captcha-edit' ) : $text; |
| 123 | + } |
| 124 | + |
| 125 | + /** |
| 126 | + * Inject whazawhoo |
| 127 | + * @fixme if multiple thingies insert a header, could break |
| 128 | + * @param SimpleTemplate $template |
| 129 | + * @return bool true to keep running callbacks |
| 130 | + */ |
| 131 | + function injectUserCreate( &$template ) { |
| 132 | + global $wgCaptchaTriggers, $wgOut; |
| 133 | + if( $wgCaptchaTriggers['createaccount'] ) { |
| 134 | + $template->set( 'header', |
| 135 | + "<div class='captcha'>" . |
| 136 | + $wgOut->parse( $this->getMessage( 'createaccount' ) ) . |
| 137 | + $this->getForm() . |
| 138 | + "</div>\n" ); |
| 139 | + } |
| 140 | + return true; |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Inject a captcha into the user login form after a failed |
| 145 | + * password attempt as a speedbump for mass attacks. |
| 146 | + * @fixme if multiple thingies insert a header, could break |
| 147 | + * @param SimpleTemplate $template |
| 148 | + * @return bool true to keep running callbacks |
| 149 | + */ |
| 150 | + function injectUserLogin( &$template ) { |
| 151 | + if( $this->isBadLoginTriggered() ) { |
| 152 | + global $wgOut; |
| 153 | + $template->set( 'header', |
| 154 | + "<div class='captcha'>" . |
| 155 | + $wgOut->parse( $this->getMessage( 'badlogin' ) ) . |
| 156 | + $this->getForm() . |
| 157 | + "</div>\n" ); |
| 158 | + } |
| 159 | + return true; |
| 160 | + } |
| 161 | + |
| 162 | + /** |
| 163 | + * When a bad login attempt is made, increment an expiring counter |
| 164 | + * in the memcache cloud. Later checks for this may trigger a |
| 165 | + * captcha display to prevent too many hits from the same place. |
| 166 | + * @param User $user |
| 167 | + * @param string $password |
| 168 | + * @param int $retval authentication return value |
| 169 | + * @return bool true to keep running callbacks |
| 170 | + */ |
| 171 | + function triggerUserLogin( $user, $password, $retval ) { |
| 172 | + global $wgCaptchaTriggers, $wgCaptchaBadLoginExpiration, $wgMemc; |
| 173 | + if( $retval == LoginForm::WRONG_PASS && $wgCaptchaTriggers['badlogin'] ) { |
| 174 | + $key = $this->badLoginKey(); |
| 175 | + $count = $wgMemc->get( $key ); |
| 176 | + if( !$count ) { |
| 177 | + $wgMemc->add( $key, 0, $wgCaptchaBadLoginExpiration ); |
| 178 | + } |
| 179 | + $count = $wgMemc->incr( $key ); |
| 180 | + } |
| 181 | + return true; |
| 182 | + } |
| 183 | + |
| 184 | + /** |
| 185 | + * Check if a bad login has already been registered for this |
| 186 | + * IP address. If so, require a captcha. |
| 187 | + * @return bool |
| 188 | + * @access private |
| 189 | + */ |
| 190 | + function isBadLoginTriggered() { |
| 191 | + global $wgMemc; |
| 192 | + return intval( $wgMemc->get( $this->badLoginKey() ) ) > 0; |
| 193 | + } |
| 194 | + |
| 195 | + /** |
| 196 | + * Internal cache key for badlogin checks. |
| 197 | + * @return string |
| 198 | + * @access private |
| 199 | + */ |
| 200 | + function badLoginKey() { |
| 201 | + return wfMemcKey( 'captcha', 'badlogin', 'ip', wfGetIP() ); |
| 202 | + } |
| 203 | + |
| 204 | + /** |
| 205 | + * Check if the submitted form matches the captcha session data provided |
| 206 | + * by the plugin when the form was generated. |
| 207 | + * |
| 208 | + * Override this! |
| 209 | + * |
| 210 | + * @param WebRequest $request |
| 211 | + * @param array $info |
| 212 | + * @return bool |
| 213 | + */ |
| 214 | + function keyMatch( $request, $info ) { |
| 215 | + return $request->getVal( 'wpCaptchaWord' ) == $info['answer']; |
| 216 | + } |
| 217 | + |
| 218 | + // ---------------------------------- |
| 219 | + |
| 220 | + /** |
| 221 | + * @param EditPage $editPage |
| 222 | + * @param string $action (edit/create/addurl...) |
| 223 | + * @return bool true if action triggers captcha on editPage's namespace |
| 224 | + */ |
| 225 | + function captchaTriggers( &$editPage, $action) { |
| 226 | + global $wgCaptchaTriggers, $wgCaptchaTriggersOnNamespace; |
| 227 | + //Special config for this NS? |
| 228 | + if (isset( $wgCaptchaTriggersOnNamespace[$editPage->mTitle->getNamespace()][$action] ) ) |
| 229 | + return $wgCaptchaTriggersOnNamespace[$editPage->mTitle->getNamespace()][$action]; |
| 230 | + |
| 231 | + return ( !empty( $wgCaptchaTriggers[$action] ) ); //Default |
| 232 | + } |
| 233 | + |
| 234 | + |
| 235 | + /** |
| 236 | + * @param EditPage $editPage |
| 237 | + * @param string $newtext |
| 238 | + * @param string $section |
| 239 | + * @return bool true if the captcha should run |
| 240 | + */ |
| 241 | + function shouldCheck( &$editPage, $newtext, $section, $merged = false ) { |
| 242 | + $this->trigger = ''; |
| 243 | + $title = $editPage->mArticle->getTitle(); |
| 244 | + |
| 245 | + global $wgUser; |
| 246 | + if( $wgUser->isAllowed( 'skipcaptcha' ) ) { |
| 247 | + wfDebug( "ConfirmEdit: user group allows skipping captcha\n" ); |
| 248 | + return false; |
| 249 | + } |
| 250 | + global $wgCaptchaWhitelistIP; |
| 251 | + if( !empty( $wgCaptchaWhitelistIP ) ) { |
| 252 | + $ip = wfGetIp(); |
| 253 | + foreach ( $wgCaptchaWhitelistIP as $range ) { |
| 254 | + if ( IP::isInRange( $ip, $range ) ) { |
| 255 | + return false; |
| 256 | + } |
| 257 | + } |
| 258 | + } |
| 259 | + |
| 260 | + |
| 261 | + global $wgEmailAuthentication, $ceAllowConfirmedEmail; |
| 262 | + if( $wgEmailAuthentication && $ceAllowConfirmedEmail && |
| 263 | + $wgUser->isEmailConfirmed() ) { |
| 264 | + wfDebug( "ConfirmEdit: user has confirmed mail, skipping captcha\n" ); |
| 265 | + return false; |
| 266 | + } |
| 267 | + |
| 268 | + if( $this->captchaTriggers( $editPage, 'edit' ) ) { |
| 269 | + // Check on all edits |
| 270 | + global $wgUser; |
| 271 | + $this->trigger = sprintf( "edit trigger by '%s' at [[%s]]", |
| 272 | + $wgUser->getName(), |
| 273 | + $title->getPrefixedText() ); |
| 274 | + $this->action = 'edit'; |
| 275 | + wfDebug( "ConfirmEdit: checking all edits...\n" ); |
| 276 | + return true; |
| 277 | + } |
| 278 | + |
| 279 | + if( $this->captchaTriggers( $editPage, 'create' ) && !$editPage->mTitle->exists() ) { |
| 280 | + //Check if creating a page |
| 281 | + global $wgUser; |
| 282 | + $this->trigger = sprintf( "Create trigger by '%s' at [[%s]]", |
| 283 | + $wgUser->getName(), |
| 284 | + $title->getPrefixedText() ); |
| 285 | + $this->action = 'create'; |
| 286 | + wfDebug( "ConfirmEdit: checking on page creation...\n" ); |
| 287 | + return true; |
| 288 | + } |
| 289 | + |
| 290 | + if( $this->captchaTriggers( $editPage, 'addurl' ) ) { |
| 291 | + // Only check edits that add URLs |
| 292 | + if ( $merged ) { |
| 293 | + // Get links from the database |
| 294 | + $oldLinks = $this->getLinksFromTracker( $title ); |
| 295 | + // Share a parse operation with Article::doEdit() |
| 296 | + $editInfo = $editPage->mArticle->prepareTextForEdit( $newtext ); |
| 297 | + $newLinks = array_keys( $editInfo->output->getExternalLinks() ); |
| 298 | + } else { |
| 299 | + // Get link changes in the slowest way known to man |
| 300 | + $oldtext = $this->loadText( $editPage, $section ); |
| 301 | + $oldLinks = $this->findLinks( $oldtext ); |
| 302 | + $newLinks = $this->findLinks( $newtext ); |
| 303 | + } |
| 304 | + |
| 305 | + $unknownLinks = array_filter( $newLinks, array( &$this, 'filterLink' ) ); |
| 306 | + $addedLinks = array_diff( $unknownLinks, $oldLinks ); |
| 307 | + $numLinks = count( $addedLinks ); |
| 308 | + |
| 309 | + if( $numLinks > 0 ) { |
| 310 | + global $wgUser; |
| 311 | + $this->trigger = sprintf( "%dx url trigger by '%s' at [[%s]]: %s", |
| 312 | + $numLinks, |
| 313 | + $wgUser->getName(), |
| 314 | + $title->getPrefixedText(), |
| 315 | + implode( ", ", $addedLinks ) ); |
| 316 | + $this->action = 'addurl'; |
| 317 | + return true; |
| 318 | + } |
| 319 | + } |
| 320 | + |
| 321 | + global $wgCaptchaRegexes; |
| 322 | + if( !empty( $wgCaptchaRegexes ) ) { |
| 323 | + // Custom regex checks |
| 324 | + $oldtext = $this->loadText( $editPage, $section ); |
| 325 | + |
| 326 | + foreach( $wgCaptchaRegexes as $regex ) { |
| 327 | + $newMatches = array(); |
| 328 | + if( preg_match_all( $regex, $newtext, $newMatches ) ) { |
| 329 | + $oldMatches = array(); |
| 330 | + preg_match_all( $regex, $oldtext, $oldMatches ); |
| 331 | + |
| 332 | + $addedMatches = array_diff( $newMatches[0], $oldMatches[0] ); |
| 333 | + |
| 334 | + $numHits = count( $addedMatches ); |
| 335 | + if( $numHits > 0 ) { |
| 336 | + global $wgUser; |
| 337 | + $this->trigger = sprintf( "%dx %s at [[%s]]: %s", |
| 338 | + $numHits, |
| 339 | + $regex, |
| 340 | + $wgUser->getName(), |
| 341 | + $title->getPrefixedText(), |
| 342 | + implode( ", ", $addedMatches ) ); |
| 343 | + $this->action = 'edit'; |
| 344 | + return true; |
| 345 | + } |
| 346 | + } |
| 347 | + } |
| 348 | + } |
| 349 | + |
| 350 | + return false; |
| 351 | + } |
| 352 | + |
| 353 | + /** |
| 354 | + * Filter callback function for URL whitelisting |
| 355 | + * @param string url to check |
| 356 | + * @return bool true if unknown, false if whitelisted |
| 357 | + * @access private |
| 358 | + */ |
| 359 | + function filterLink( $url ) { |
| 360 | + global $wgCaptchaWhitelist; |
| 361 | + $source = wfMsgForContent( 'captcha-addurl-whitelist' ); |
| 362 | + |
| 363 | + $whitelist = wfEmptyMsg( 'captcha-addurl-whitelist', $source ) |
| 364 | + ? false |
| 365 | + : $this->buildRegexes( explode( "\n", $source ) ); |
| 366 | + |
| 367 | + $cwl = $wgCaptchaWhitelist !== false ? preg_match( $wgCaptchaWhitelist, $url ) : false; |
| 368 | + $wl = $whitelist !== false ? preg_match( $whitelist, $url ) : false; |
| 369 | + |
| 370 | + return !( $cwl || $wl ); |
| 371 | + } |
| 372 | + |
| 373 | + /** |
| 374 | + * Build regex from whitelist |
| 375 | + * @param string lines from [[MediaWiki:Captcha-addurl-whitelist]] |
| 376 | + * @return string Regex or bool false if whitelist is empty |
| 377 | + * @access private |
| 378 | + */ |
| 379 | + function buildRegexes( $lines ) { |
| 380 | + # Code duplicated from the SpamBlacklist extension (r19197) |
| 381 | + |
| 382 | + # Strip comments and whitespace, then remove blanks |
| 383 | + $lines = array_filter( array_map( 'trim', preg_replace( '/#.*$/', '', $lines ) ) ); |
| 384 | + |
| 385 | + # No lines, don't make a regex which will match everything |
| 386 | + if ( count( $lines ) == 0 ) { |
| 387 | + wfDebug( "No lines\n" ); |
| 388 | + return false; |
| 389 | + } else { |
| 390 | + # Make regex |
| 391 | + # It's faster using the S modifier even though it will usually only be run once |
| 392 | + //$regex = 'http://+[a-z0-9_\-.]*(' . implode( '|', $lines ) . ')'; |
| 393 | + //return '/' . str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $regex) ) . '/Si'; |
| 394 | + $regexes = ''; |
| 395 | + $regexStart = '/http:\/\/+[a-z0-9_\-.]*('; |
| 396 | + $regexEnd = ')/Si'; |
| 397 | + $regexMax = 4096; |
| 398 | + $build = false; |
| 399 | + foreach( $lines as $line ) { |
| 400 | + // FIXME: not very robust size check, but should work. :) |
| 401 | + if( $build === false ) { |
| 402 | + $build = $line; |
| 403 | + } elseif( strlen( $build ) + strlen( $line ) > $regexMax ) { |
| 404 | + $regexes .= $regexStart . |
| 405 | + str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $build) ) . |
| 406 | + $regexEnd; |
| 407 | + $build = $line; |
| 408 | + } else { |
| 409 | + $build .= '|' . $line; |
| 410 | + } |
| 411 | + } |
| 412 | + if( $build !== false ) { |
| 413 | + $regexes .= $regexStart . |
| 414 | + str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $build) ) . |
| 415 | + $regexEnd; |
| 416 | + } |
| 417 | + return $regexes; |
| 418 | + } |
| 419 | + } |
| 420 | + |
| 421 | + /** |
| 422 | + * Load external links from the externallinks table |
| 423 | + */ |
| 424 | + function getLinksFromTracker( $title ) { |
| 425 | + $dbr =& wfGetDB( DB_SLAVE ); |
| 426 | + $id = $title->getArticleId(); // should be zero queries |
| 427 | + $res = $dbr->select( 'externallinks', array( 'el_to' ), |
| 428 | + array( 'el_from' => $id ), __METHOD__ ); |
| 429 | + $links = array(); |
| 430 | + while ( $row = $dbr->fetchObject( $res ) ) { |
| 431 | + $links[] = $row->el_to; |
| 432 | + } |
| 433 | + return $links; |
| 434 | + } |
| 435 | + |
| 436 | + /** |
| 437 | + * The main callback run on edit attempts. |
| 438 | + * @param EditPage $editPage |
| 439 | + * @param string $newtext |
| 440 | + * @param string $section |
| 441 | + * @param bool true to continue saving, false to abort and show a captcha form |
| 442 | + */ |
| 443 | + function confirmEdit( &$editPage, $newtext, $section, $merged = false ) { |
| 444 | + if( $this->shouldCheck( $editPage, $newtext, $section, $merged ) ) { |
| 445 | + if( $this->passCaptcha() ) { |
| 446 | + return true; |
| 447 | + } else { |
| 448 | + $editPage->showEditForm( array( &$this, 'editCallback' ) ); |
| 449 | + return false; |
| 450 | + } |
| 451 | + } else { |
| 452 | + wfDebug( "ConfirmEdit: no need to show captcha.\n" ); |
| 453 | + return true; |
| 454 | + } |
| 455 | + } |
| 456 | + |
| 457 | + /** |
| 458 | + * A more efficient edit filter callback based on the text after section merging |
| 459 | + * @param EditPage $editPage |
| 460 | + * @param string $newtext |
| 461 | + */ |
| 462 | + function confirmEditMerged( &$editPage, $newtext ) { |
| 463 | + return $this->confirmEdit( $editPage, $newtext, false, true ); |
| 464 | + } |
| 465 | + |
| 466 | + /** |
| 467 | + * Hook for user creation form submissions. |
| 468 | + * @param User $u |
| 469 | + * @param string $message |
| 470 | + * @return bool true to continue, false to abort user creation |
| 471 | + */ |
| 472 | + function confirmUserCreate( $u, &$message ) { |
| 473 | + global $wgCaptchaTriggers; |
| 474 | + if( $wgCaptchaTriggers['createaccount'] ) { |
| 475 | + $this->trigger = "new account '" . $u->getName() . "'"; |
| 476 | + if( !$this->passCaptcha() ) { |
| 477 | + $message = wfMsg( 'captcha-createaccount-fail' ); |
| 478 | + return false; |
| 479 | + } |
| 480 | + } |
| 481 | + return true; |
| 482 | + } |
| 483 | + |
| 484 | + /** |
| 485 | + * Hook for user login form submissions. |
| 486 | + * @param User $u |
| 487 | + * @param string $message |
| 488 | + * @return bool true to continue, false to abort user creation |
| 489 | + */ |
| 490 | + function confirmUserLogin( $u, $pass, &$retval ) { |
| 491 | + if( $this->isBadLoginTriggered() ) { |
| 492 | + $this->trigger = "post-badlogin login '" . $u->getName() . "'"; |
| 493 | + if( !$this->passCaptcha() ) { |
| 494 | + $message = wfMsg( 'captcha-badlogin-fail' ); |
| 495 | + // Emulate a bad-password return to confuse the shit out of attackers |
| 496 | + $retval = LoginForm::WRONG_PASS; |
| 497 | + return false; |
| 498 | + } |
| 499 | + } |
| 500 | + return true; |
| 501 | + } |
| 502 | + |
| 503 | + /** |
| 504 | + * Given a required captcha run, test form input for correct |
| 505 | + * input on the open session. |
| 506 | + * @return bool if passed, false if failed or new session |
| 507 | + */ |
| 508 | + function passCaptcha() { |
| 509 | + $info = $this->retrieveCaptcha(); |
| 510 | + if( $info ) { |
| 511 | + global $wgRequest; |
| 512 | + if( $this->keyMatch( $wgRequest, $info ) ) { |
| 513 | + $this->log( "passed" ); |
| 514 | + $this->clearCaptcha( $info ); |
| 515 | + return true; |
| 516 | + } else { |
| 517 | + $this->clearCaptcha( $info ); |
| 518 | + $this->log( "bad form input" ); |
| 519 | + return false; |
| 520 | + } |
| 521 | + } else { |
| 522 | + $this->log( "new captcha session" ); |
| 523 | + return false; |
| 524 | + } |
| 525 | + } |
| 526 | + |
| 527 | + /** |
| 528 | + * Log the status and any triggering info for debugging or statistics |
| 529 | + * @param string $message |
| 530 | + */ |
| 531 | + function log( $message ) { |
| 532 | + wfDebugLog( 'captcha', 'ConfirmEdit: ' . $message . '; ' . $this->trigger ); |
| 533 | + } |
| 534 | + |
| 535 | + /** |
| 536 | + * Generate a captcha session ID and save the info in PHP's session storage. |
| 537 | + * (Requires the user to have cookies enabled to get through the captcha.) |
| 538 | + * |
| 539 | + * A random ID is used so legit users can make edits in multiple tabs or |
| 540 | + * windows without being unnecessarily hobbled by a serial order requirement. |
| 541 | + * Pass the returned id value into the edit form as wpCaptchaId. |
| 542 | + * |
| 543 | + * @param array $info data to store |
| 544 | + * @return string captcha ID key |
| 545 | + */ |
| 546 | + function storeCaptcha( $info ) { |
| 547 | + if( !isset( $info['index'] ) ) { |
| 548 | + // Assign random index if we're not udpating |
| 549 | + $info['index'] = strval( mt_rand() ); |
| 550 | + } |
| 551 | + $this->storage->store( $info['index'], $info ); |
| 552 | + return $info['index']; |
| 553 | + } |
| 554 | + |
| 555 | + /** |
| 556 | + * Fetch this session's captcha info. |
| 557 | + * @return mixed array of info, or false if missing |
| 558 | + */ |
| 559 | + function retrieveCaptcha() { |
| 560 | + global $wgRequest; |
| 561 | + $index = $wgRequest->getVal( 'wpCaptchaId' ); |
| 562 | + return $this->storage->retrieve( $index ); |
| 563 | + } |
| 564 | + |
| 565 | + /** |
| 566 | + * Clear out existing captcha info from the session, to ensure |
| 567 | + * it can't be reused. |
| 568 | + */ |
| 569 | + function clearCaptcha( $info ) { |
| 570 | + $this->storage->clear( $info['index'] ); |
| 571 | + } |
| 572 | + |
| 573 | + /** |
| 574 | + * Retrieve the current version of the page or section being edited... |
| 575 | + * @param EditPage $editPage |
| 576 | + * @param string $section |
| 577 | + * @return string |
| 578 | + * @access private |
| 579 | + */ |
| 580 | + function loadText( $editPage, $section ) { |
| 581 | + $rev = Revision::newFromTitle( $editPage->mTitle ); |
| 582 | + if( is_null( $rev ) ) { |
| 583 | + return ""; |
| 584 | + } else { |
| 585 | + $text = $rev->getText(); |
| 586 | + if( $section != '' ) { |
| 587 | + return Article::getSection( $text, $section ); |
| 588 | + } else { |
| 589 | + return $text; |
| 590 | + } |
| 591 | + } |
| 592 | + } |
| 593 | + |
| 594 | + /** |
| 595 | + * Extract a list of all recognized HTTP links in the text. |
| 596 | + * @param string $text |
| 597 | + * @return array of strings |
| 598 | + */ |
| 599 | + function findLinks( $text ) { |
| 600 | + global $wgParser, $wgTitle, $wgUser; |
| 601 | + |
| 602 | + $options = new ParserOptions(); |
| 603 | + $text = $wgParser->preSaveTransform( $text, $wgTitle, $wgUser, $options ); |
| 604 | + $out = $wgParser->parse( $text, $wgTitle, $options ); |
| 605 | + |
| 606 | + return array_keys( $out->getExternalLinks() ); |
| 607 | + } |
| 608 | + |
| 609 | + /** |
| 610 | + * Show a page explaining what this wacky thing is. |
| 611 | + */ |
| 612 | + function showHelp() { |
| 613 | + global $wgOut, $ceAllowConfirmedEmail; |
| 614 | + $wgOut->setPageTitle( wfMsg( 'captchahelp-title' ) ); |
| 615 | + $wgOut->addWikiText( wfMsg( 'captchahelp-text' ) ); |
| 616 | + if ( $this->storage->cookiesNeeded() ) { |
| 617 | + $wgOut->addWikiText( wfMsg( 'captchahelp-cookies-needed' ) ); |
| 618 | + } |
| 619 | + } |
| 620 | + |
| 621 | +} |
| 622 | + |
| 623 | +class CaptchaSessionStore { |
| 624 | + function store( $index, $info ) { |
| 625 | + $_SESSION['captcha' . $info['index']] = $info; |
| 626 | + } |
| 627 | + |
| 628 | + function retrieve( $index ) { |
| 629 | + if( isset( $_SESSION['captcha' . $index] ) ) { |
| 630 | + return $_SESSION['captcha' . $index]; |
| 631 | + } else { |
| 632 | + return false; |
| 633 | + } |
| 634 | + } |
| 635 | + |
| 636 | + function clear( $index ) { |
| 637 | + unset( $_SESSION['captcha' . $index] ); |
| 638 | + } |
| 639 | + |
| 640 | + function cookiesNeeded() { |
| 641 | + return true; |
| 642 | + } |
| 643 | +} |
| 644 | + |
| 645 | +class CaptchaCacheStore { |
| 646 | + function store( $index, $info ) { |
| 647 | + global $wgMemc, $wgCaptchaSessionExpiration; |
| 648 | + $wgMemc->set( wfMemcKey( 'captcha', $index ), $info, |
| 649 | + $wgCaptchaSessionExpiration ); |
| 650 | + } |
| 651 | + |
| 652 | + function retrieve( $index ) { |
| 653 | + global $wgMemc; |
| 654 | + $info = $wgMemc->get( wfMemcKey( 'captcha', $index ) ); |
| 655 | + if( $info ) { |
| 656 | + return $info; |
| 657 | + } else { |
| 658 | + return false; |
| 659 | + } |
| 660 | + } |
| 661 | + |
| 662 | + function clear( $index ) { |
| 663 | + global $wgMemc; |
| 664 | + $wgMemc->delete( wfMemcKey( 'captcha', $index ) ); |
| 665 | + } |
| 666 | + |
| 667 | + function cookiesNeeded() { |
| 668 | + return false; |
| 669 | + } |
| 670 | +} |
| 671 | + |
Property changes on: trunk/extensions/ConfirmEdit/ConfirmEdit_body.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 672 | + native |
Index: trunk/extensions/ConfirmEdit/ConfirmEdit.i18n.php |
— | — | @@ -5,9 +5,9 @@ |
6 | 6 | * @addtogroup Extensions |
7 | 7 | */ |
8 | 8 | |
9 | | -$wgConfirmEditMessages = array(); |
| 9 | +$messages = array(); |
10 | 10 | |
11 | | -$wgConfirmEditMessages['en'] = array( |
| 11 | +$messages['en'] = array( |
12 | 12 | 'captcha-edit' => 'To edit this article, please solve the simple sum below and enter the answer in |
13 | 13 | the box ([[Special:Captcha/help|more info]]):', |
14 | 14 | 'captcha-addurl' => 'Your edit includes new external links. To help protect against automated |
— | — | @@ -36,7 +36,7 @@ |
37 | 37 | #</pre> <!-- leave this line exactly as it is -->', |
38 | 38 | ); |
39 | 39 | |
40 | | -$wgConfirmEditMessages['af'] = array( |
| 40 | +$messages['af'] = array( |
41 | 41 | 'captcha-edit' => "U wysiging bevat nuwe webskakels. Neem kennis dat blote reklame van u werf, produk of besigheid as vandalisme beskou kan word. As beskerming teen outomatiese gemorsbydraes, sal u die woorde wat onder verskyn in die prentjie moet intik: <br />([[Spesiaal:Captcha/help|Wat is hierdie?]])", |
42 | 42 | 'captcha-addurl' => "U wysiging bevat nuwe webskakels. Neem kennis dat blote reklame van u werf, produk of besigheid as vandalisme beskou kan word. As beskerming teen outomatiese gemorsbydraes, sal u die woorde wat onder verskyn in die prentjie moet intik: <br />([[Spesiaal:Captcha/help|Wat is hierdie?]])", |
43 | 43 | 'captcha-create' => "U wysiging bevat nuwe webskakels. Neem kennis dat blote reklame van u werf, produk of besigheid as vandalisme beskou kan word. As beskerming teen outomatiese gemorsbydraes, sal u die woorde wat onder verskyn in die prentjie moet intik: <br />([[Spesiaal:Captcha/help|Wat is hierdie?]])", |
— | — | @@ -45,10 +45,10 @@ |
46 | 46 | 'captcha-createaccount' => "As 'n beskerming teen geoutomatiseerde gemors, tik asseblief die woorde wat in die beeld verskyn in om 'n rekening te skep: <br />([[Special:Captcha/help|Wat is hierdie?]])", |
47 | 47 | 'captcha-createaccount-fail' => "Verkeerde of geen bevestigingkode.", |
48 | 48 | ); |
49 | | -$wgConfirmEditMessages['am'] = array( |
| 49 | +$messages['am'] = array( |
50 | 50 | 'captcha-createaccount' => 'ያልተፈለገ የመኪናነት አባልነት ለመከላከል፥ አባል ለመሆን በዚህ ምስል የታዩት እንግሊዝኛ ቃላት ወይም ቁጥር መልስ በትክክል መጻፍ ግዴታ ነው። ([[Special:Captcha/help|ይህ ምንድነው?]]):', |
51 | 51 | ); |
52 | | -$wgConfirmEditMessages['ar'] = array( |
| 52 | +$messages['ar'] = array( |
53 | 53 | 'captcha-edit' => 'يحتوي تعديلك هذا على وصلات خارجية. للحماية من السخام الأوتوماتيكي، قم من فضلك بحل المسألة الرياضية البسيطة أدناه وأدخل الحل في الصندوق ([[Special:Captcha/help|مزيد من المعلومات]]):', |
54 | 54 | 'captcha-addurl' => 'تعديلك يحتوي على وصلات خارجية جديدة. للمساعدة في الحماية من السخام الأوتوماتيكي، من فضلك حل عملية الجمع بالأسفل و أضف الحل في الصندوق ([[Special::Captcha/help|معلومات إضافية]]):', |
55 | 55 | 'captcha-badlogin' => 'للمساعدة في الحماية ضد سرقة كلمات السر، من فضلك حل عملية الجمع البسيطة بالأسفل و أدخل الحل في الصندوق ([[Special:Captcha/help|معلومات إضافية]]):', |
— | — | @@ -71,11 +71,11 @@ |
72 | 72 | # * كل سطر غير فارغ هو قطعة ريجيكس والتي توافق فقط المعيلين داخل المسارات |
73 | 73 | #</pre> <!-- leave this line exactly as it is -->', |
74 | 74 | ); |
75 | | -$wgConfirmEditMessages['bcl'] = array( |
| 75 | +$messages['bcl'] = array( |
76 | 76 | 'captcha-create' => 'Tangarig maggibo an pahina, paki simbagan an simpleng suma sa ibaba asin ikaag an simbag sa laog kan kahon ([[Special:Captcha/help|more info]]):', |
77 | 77 | 'captchahelp-title' => 'Tabang sa Captcha', |
78 | 78 | ); |
79 | | -$wgConfirmEditMessages['br'] = array( |
| 79 | +$messages['br'] = array( |
80 | 80 | 'captcha-edit' => 'Liammoù diavaez nevez zo bet ouzhpennet ganeoc\'h. A-benn en em wareziñ diouzh ar spam emgefre skrivit disoc\'h ar jedadennig eeun-mañ er stern : <br />([[Special:Captcha/help|Petra eo se?]])', |
81 | 81 | 'captcha-addurl' => 'Liammoù diavaez nevez zo bet ouzhpennet ganeoc\'h. A-benn en em wareziñ diouzh ar spam emgefre skrivit disoc\'h ar jedadennig eeun-mañ er stern : <br />([[Special:Captcha/help|Petra eo se?]])', |
82 | 82 | 'captcha-create' => 'Liammoù diavaez nevez zo bet ouzhpennet ganeoc\'h. A-benn en em wareziñ diouzh ar spam emgefre skrivit disoc\'h ar jedadennig eeun-mañ er stern : <br />([[Special:Captcha/help|Petra eo se?]])', |
— | — | @@ -84,7 +84,7 @@ |
85 | 85 | 'captchahelp-title' => 'Skoazell Capcha', |
86 | 86 | 'captchahelp-text' => 'Alies e vez taget al lec\'hiennoù a zegemer kemennadennoù a-berzh an holl, evel ar wiki-mañ, gant ar spamerien a implij ostilhoù emgefre evit postañ o liammoù war lec\'hiennoù a bep seurt. Diverket e c\'hallont bezañ, gwir eo, kazus-mat ez int memes tra. A-wechoù, dreist-holl pa vez ouzhpennet liammoù Web nevez war ur bajenn, e c\'hallo ar wiki-mañ diskouez deoc\'h ur skeudenn warni un tamm testenn liv pe a-dreuz. Goulennet e vo diganeoc\'h skrivañ ar gerioù deuet war wel. Un trevell start da emgefrekaat eo hemañ. Gant se e c\'hallo an implijerien wirion postañ ar pezh a fel ldezho tra ma vo lakaet un harz d\'an darn vrasañ eus ar spamerien pe d\'an dagerien robotek all. Koulskoude e c\'hallo an implijerien berr o gweled pe ar re a implij merdeerioù diazezet war ar skrid pe war ar vouezh bezañ strafuilhet gant se. N\'omp ket evit kinnig un diskoulm dre glevet evit c\'hoazh. Kit e darempred gant merourien al lec\'hienn m\'hoc\'h eus diaesterioù evit kemer perzh abalamour d\'an teknik-se. Pouezit war bouton \'kent\' ho merdeer evit distreiñ d\'ar bajenn gemmañ.', |
87 | 87 | ); |
88 | | -$wgConfirmEditMessages['bs'] = array( |
| 88 | +$messages['bs'] = array( |
89 | 89 | 'captcha-edit' => 'Vaša izmjena uključuje nove URL poveznice; kao zaštita od automatizovanog vandalizma, moraćete da ukucate riječi koje su prikazane u slici: |
90 | 90 | <br />([[{{ns:special}}:Captcha/help|Šta je ovo?]])', |
91 | 91 | 'captcha-addurl' => 'Vaša izmjena uključuje nove URL poveznice; kao zaštita od automatizovanog vandalizma, moraćete da ukucate riječi koje su prikazane u slici: |
— | — | @@ -102,7 +102,7 @@ |
103 | 103 | <br />([[{{ns:special}}:Captcha/help|Šta je ovo?]])', |
104 | 104 | 'captcha-createaccount-fail' => 'Netačan unos ili nedostatak šifre za potvrđivanje.', |
105 | 105 | ); |
106 | | -$wgConfirmEditMessages['ca'] = array( |
| 106 | +$messages['ca'] = array( |
107 | 107 | 'captcha-edit' => 'Per a poder editar aquest article cal que resolgueu aquesta simple suma i introduïu el resultat en el quadre ([[Special:Captcha/help|més informació]]):', |
108 | 108 | 'captcha-addurl' => 'La vostra edició conté enllaços externs nous. Com a protecció contra la brossa de propaganda automàtica, cal que resolgueu aquesta simple suma i introduïu el resultat en el quadre a continuació ([[Special:Captcha/help|més informació]]):', |
109 | 109 | 'captcha-badlogin' => 'Per a ajudar en la protecció contra l\'obtenció automatitzada de contrasenyes haureu de resoldre la suma que apareix a continuació ([[Special:Captcha/help|més informació]]):', |
— | — | @@ -121,7 +121,7 @@ |
122 | 122 | |
123 | 123 | Cliqueu el botó de retrocedir del vostre navegador per a tornar al formulari.', |
124 | 124 | ); |
125 | | -$wgConfirmEditMessages['cs'] = array( |
| 125 | +$messages['cs'] = array( |
126 | 126 | 'captcha-badlogin' => 'V rámci ochrany před automatickým pokusům uhodnout heslo musíte vyřešit následující jednoduchý součet a napsat výsledek. ([[Special:Captcha/help|Co tohle znamená?]]):', |
127 | 127 | 'captchahelp-cookies-needed' => "Musíte mít zapnuty cookies ve svém prohlížeči.", |
128 | 128 | 'captcha-edit' => 'Abyste mohli editovat tuto stránku, musíte vyřešit následující jednoduchý součet a napsat výsledek. ([[Special:Captcha/help|Co tohle znamená?]])', |
— | — | @@ -138,7 +138,7 @@ |
139 | 139 | 'captcha-createaccount' => 'V rámci ochrany před automatickým vytvářením účtů musíte pro provedení registrace vyřešit následující jednoduchý součet a napsat výsledek. ([[Special:Captcha/help|Co tohle znamená?]])', |
140 | 140 | 'captcha-createaccount-fail' => 'Chybějící či neplatný potvrzovací kód.', |
141 | 141 | ); |
142 | | -$wgConfirmEditMessages['cy'] = array( |
| 142 | +$messages['cy'] = array( |
143 | 143 | 'captcha-edit' => "Mae eich golygiad yn cynnwys cysylltiadau URL newydd. Er mwyn profi nad ydych yn beiriant sbam, teipiwch y geiriau canlynol yn y blwch isod os gwelwch yn dda. <br />([[Arbennig:Captcha/help|Mwy o wybodaeth]])", |
144 | 144 | 'captcha-addurl' => "Mae eich golygiad yn cynnwys cysylltiadau URL newydd. Er mwyn profi nad ydych yn beiriant sbam, teipiwch y geiriau canlynol yn y blwch isod os gwelwch yn dda. <br />([[Arbennig:Captcha/help|Mwy o wybodaeth]])", |
145 | 145 | 'captcha-create' => "Mae eich golygiad yn cynnwys cysylltiadau URL newydd. Er mwyn profi nad ydych yn beiriant sbam, teipiwch y geiriau canlynol yn y blwch isod os gwelwch yn dda. <br />([[Arbennig:Captcha/help|Mwy o wybodaeth]])", |
— | — | @@ -147,7 +147,7 @@ |
148 | 148 | 'captcha-createaccount' => "Teipiwch y geiriau sy'n ymddangos yn y ddelwedd isod os gwelwch yn dda. Mae'r nodwedd hon yn rhwystro rhaglenni sbam rhag creu cyfrifon i'w hunain. <br />([[Arbennig:Captcha/help|Mwy o wybodaeth]])", |
149 | 149 | 'captcha-createaccount-fail' => "Côd cadarnhau ar goll neu'n anghywir.", |
150 | 150 | ); |
151 | | -$wgConfirmEditMessages['da'] = array( |
| 151 | +$messages['da'] = array( |
152 | 152 | 'captcha-edit' => 'For at redigere denne side, skal du give svaret på regnestyket nedenfor, og angive resultatet i feltet under det. ([[Special:Captcha/help|mere information]]):', |
153 | 153 | 'captcha-addurl' => 'Din redigering tilføjer nye eksterne henvisninger til artiklen. Som beskyttelse mod automatiseret spam, skal du give svaret på regnestyket nedenfor, og angive resultatet i feltet under det. ([[Special:Captcha/help|mere information]]):', |
154 | 154 | 'captcha-badlogin' => 'For at beskytte mod automatiserede gæt på kodeord, skal du give svaret på regnestyket nedenfor, og angive resultatet i feltet under det. ([[Special:Captcha/help|mere information]]):', |
— | — | @@ -171,7 +171,7 @@ |
172 | 172 | #</pre> <!-- Undlad at rette denne linie -->', |
173 | 173 | ); |
174 | 174 | |
175 | | -$wgConfirmEditMessages['de'] = array( |
| 175 | +$messages['de'] = array( |
176 | 176 | 'captcha-edit' => "Zur Bearbeitung der Seite löse die nachfolgende Rechenaufgabe und trage das Ergebnis in das Feld unten ein [[{{ns:special}}:Captcha/help|(Fragen oder Probleme?)]].", |
177 | 177 | 'captcha-addurl' => "Deine Bearbeitung enthält neue externe Links. Zum Schutz vor automatisiertem Spamming löse die nachfolgende Rechenaufgabe und trage das Ergebnis in das Feld unten ein. Klicke dann erneut auf „Seite speichern“ [[{{ns:special}}:Captcha/help|(Fragen oder Probleme?)]].", |
178 | 178 | 'captcha-badlogin' => 'Zum Schutz vor einer Kompromittierung deines Benutzerkontos löse die nachfolgende Rechenaufgabe und trage das Ergebnis in das Feld unten ein [[{{ns:special}}:Captcha/help|(Fragen oder Probleme?)]]:', |
— | — | @@ -189,7 +189,7 @@ |
190 | 190 | #</pre> <!-- leave this line exactly as it is -->', |
191 | 191 | ); |
192 | 192 | |
193 | | -$wgConfirmEditMessages['es'] = array( |
| 193 | +$messages['es'] = array( |
194 | 194 | 'captcha-edit' => 'Para editar este artículo, por favor resuelve la sencilla suma que aparece abajo e introduce la solución en la caja ([[Special:Captcha/help|más información]]):', |
195 | 195 | 'captcha-addurl' => 'Tu edición incluye nuevos enlaces externos. Para ayudar a proteger contra el spam automatizado, por favor resuelve la sencilla suma de abajo e introduce la respuesta en la caja ([[Special:Captcha/help|más información]]):', |
196 | 196 | 'captcha-createaccount' => 'Para ayudar a protegernos de la creación automática de cuentas, por favor resuelve la simple suma de abajo e introduce la respuesta en la caja ([[Special:Captcha/help|más información]]):', |
— | — | @@ -202,7 +202,7 @@ |
203 | 203 | En ocasiones, especialmente cuando añada nuevos enlaces a una página, la wiki le mostrará una imagen de texto coloreado o distorsionado y le pedirá que escriba las palabras que muestra. Dado que esta es una tarea difícil de automatizar, permite a la mayoría de las personas enviar sus textos, a la vez que detiene a la mayoría de los spammers y otros atacantes automáticos.', |
204 | 204 | ); |
205 | 205 | |
206 | | -$wgConfirmEditMessages['et'] = array( |
| 206 | +$messages['et'] = array( |
207 | 207 | 'captcha-edit' => "Teie muudatuses on uusi linke; kaitseks spämmi vastu peate sisestama järgneval pildil olevad sõnad:<br /> ([[Special:Captcha/help|Mis see on?]])", |
208 | 208 | 'captcha-addurl' => "Teie muudatuses on uusi linke; kaitseks spämmi vastu peate sisestama järgneval pildil olevad sõnad:<br /> ([[Special:Captcha/help|Mis see on?]])", |
209 | 209 | 'captcha-create' => "Teie muudatuses on uusi linke; kaitseks spämmi vastu peate sisestama järgneval pildil olevad sõnad:<br /> ([[Special:Captcha/help|Mis see on?]])", |
— | — | @@ -211,7 +211,7 @@ |
212 | 212 | 'captcha-createaccount' => "Kaitsena spämmi vastu peate konto registreerimiseks lahtrisse kirjutama järgneva tehte tulemuse.<br /> ([[Special:Captcha/help|Mis see on?]])", |
213 | 213 | 'captcha-createaccount-fail' => "Puuduv või valesti sisestatud kinnituskood.", |
214 | 214 | ); |
215 | | -$wgConfirmEditMessages['eu'] = array( |
| 215 | +$messages['eu'] = array( |
216 | 216 | 'captcha-edit' => "Zure aldaketan URL lotura berriak daude; spam-a saihesteko, jarraian dagoen irudiko hitzak idaztea beharrezkoa da:<br /> ([[Special:Captcha/help|Zer da hau?]])", |
217 | 217 | 'captcha-addurl' => "Zure aldaketan URL lotura berriak daude; spam-a saihesteko, jarraian dagoen irudiko hitzak idaztea beharrezkoa da:<br /> ([[Special:Captcha/help|Zer da hau?]])", |
218 | 218 | 'captcha-create' => "Zure aldaketan URL lotura berriak daude; spam-a saihesteko, jarraian dagoen irudiko hitzak idaztea beharrezkoa da:<br /> ([[Special:Captcha/help|Zer da hau?]])", |
— | — | @@ -221,7 +221,7 @@ |
222 | 222 | 'captcha-createaccount-fail' => "Baieztatze kode ezegokia.", |
223 | 223 | ); |
224 | 224 | |
225 | | -$wgConfirmEditMessages['fi'] = array( |
| 225 | +$messages['fi'] = array( |
226 | 226 | 'captcha-edit' => 'Muokkauksesi sisältää uusia linkkejä muille sivuille. Ratkaise alla oleva summa jatkaaksesi ([[Special:Captcha/help|lisätietoja]]):', |
227 | 227 | 'captcha-addurl' => 'Muokkauksesi sisältää uusia linkkejä muille sivuille. Ratkaise alla oleva summa jatkaaksesi ([[Special:Captcha/help|lisätietoja]]):', |
228 | 228 | 'captcha-create' => 'Muokkauksesi sisältää uusia linkkejä muille sivuille. Ratkaise alla oleva summa jatkaaksesi ([[Special:Captcha/help|lisätietoja]]):', |
— | — | @@ -238,7 +238,7 @@ |
239 | 239 | |
240 | 240 | Voit palata muokkaustilaan selaimen paluutoiminnolla.", |
241 | 241 | ); |
242 | | -$wgConfirmEditMessages['fr'] = array( |
| 242 | +$messages['fr'] = array( |
243 | 243 | 'captcha-edit' => 'Votre édition inclut de nouveaux liens externes. Comme protection contre le pourriel automatique, veuillez entrer le résultat de l’opération ci-dessous dans la boîte ([[Special:Captcha/help|plus d’informations]]) :', |
244 | 244 | 'captcha-addurl' => 'Votre édition inclut de nouveaux liens externes. Comme protection contre le pourriel automatique, veuillez entrer le résultat de l’opération ci-dessous dans la boîte ([[Special:Captcha/help|plus d’informations]]) :', |
245 | 245 | 'captcha-badlogin' => 'Pour essayer de contourner les tentatives de crackage de mots de passe automatisées par des robots, veuillez recopier le texte ci-dessous dans la boîte de texte placée au dessous de celui-ci. ([[Special:Captcha/aide|Plus d’infos]])', |
— | — | @@ -255,7 +255,7 @@ |
256 | 256 | |
257 | 257 | Cliquez sur le bouton « Précédent » de votre navigateur pour revenir à la page d’édition.', |
258 | 258 | ); |
259 | | -$wgConfirmEditMessages['ga'] = array( |
| 259 | +$messages['ga'] = array( |
260 | 260 | 'captcha-edit' => "Tá naisc URL nua san athrú seo atá tú ar tí a dhéanamh; mar chosaint in éadan turscair uathoibrithe, caithfidh tú na focail san íomhá seo a ionchur: <br />([[Speisialta:Captcha/help|Céard é seo?]])", |
261 | 261 | 'captcha-addurl' => "Tá naisc URL nua san athrú seo atá tú ar tí a dhéanamh; mar chosaint in éadan turscair uathoibrithe, caithfidh tú na focail san íomhá seo a ionchur: <br />([[Speisialta:Captcha/help|Céard é seo?]])", |
262 | 262 | 'captcha-create' => "Tá naisc URL nua san athrú seo atá tú ar tí a dhéanamh; mar chosaint in éadan turscair uathoibrithe, caithfidh tú na focail san íomhá seo a ionchur: <br />([[Speisialta:Captcha/help|Céard é seo?]])", |
— | — | @@ -270,7 +270,7 @@ |
271 | 271 | 'captcha-createaccount' => "Mar chosaint in éadan turscair uathoibrithe, caithfidh tú na focail san íomhá seo a ionchur chun cuntas a chlárú: <br />([[Speisialta:Captcha/help|Céard é seo?]])", |
272 | 272 | 'captcha-createaccount-fail' => "Ní raibh an cód deimhnithe ceart sa bhosca, nó ní raibh aon chód ann ar chor ar bith.", |
273 | 273 | ); |
274 | | -$wgConfirmEditMessages['gl'] = array( |
| 274 | +$messages['gl'] = array( |
275 | 275 | 'captcha-edit' => 'A súa edición inclúe novos enderezos URL; como protección contra as ferramentas de publicación automática de ligazóns publicitarias necesita teclear as palabras que aparecen nesta imaxe:<br /> ([[Special:Captcha/help|Qué é isto?]])', |
276 | 276 | 'captcha-addurl' => 'A súa edición inclúe novos enderezos URL; como protección contra as ferramentas de publicación automática de ligazóns publicitarias necesita teclear as palabras que aparecen nesta imaxe:<br /> ([[Special:Captcha/help|Qué é isto?]])', |
277 | 277 | 'captcha-badlogin' => 'Como protección para que non descubran o contrasinal por medios automáticos, resolva a suma simple de embaixo e introduza a resposta na caixa ([[Special:Captcha/help|máis información]])', |
— | — | @@ -286,7 +286,7 @@ |
287 | 287 | # * Cada liña que non estea en branco é un fragmento de expresión regular que só coincidirá con hosts dentro de URLs |
288 | 288 | #</pre> <!-- deixe esta liña exactamente como está -->', |
289 | 289 | ); |
290 | | -$wgConfirmEditMessages['he'] = array( |
| 290 | +$messages['he'] = array( |
291 | 291 | 'captcha-edit' => 'כדי לערוך את הדף, אנא פיתרו את תרגיל החיבור הפשוט שלהלן והקלידו את התשובה בתיבה ([[{{ns:special}}:Captcha/help|מידע נוסף]]):', |
292 | 292 | 'captcha-addurl' => 'עריכתכם כוללת קישורים חיצוניים חדשים. כהגנה מפני ספאם אוטומטי, אנא פיתרו את תרגיל החיבור הפשוט שלהלן והקלידו את התשובה בתיבה ([[{{ns:special}}:Captcha/help|מידע נוסף]]):', |
293 | 293 | 'captcha-badlogin' => 'כהגנה מפני פריצת סיסמאות אוטומטית, אנא פיתרו את תרגיל החיבור הפשוט שלהלן והקלידו את התשובה בתיבה ([[{{ns:special}}:Captcha/help|מידע נוסף]]):', |
— | — | @@ -309,7 +309,7 @@ |
310 | 310 | # * כל שורה לא ריקה היא ביטוי רגולרי שיתאים לאתרים בכתובות URL |
311 | 311 | #</pre> <!-- יש להשאיר שורה זו בדיוק כפי שהיא כתובה -->', |
312 | 312 | ); |
313 | | -$wgConfirmEditMessages['hr'] = array( |
| 313 | +$messages['hr'] = array( |
314 | 314 | 'captcha-edit' => "Vaše uređivanje sadrži nove vanjske poveznice. Kao zaštitu od automatskog spama, trebate unijeti slova koja vidite na slici: <br />([[Posebno:Captcha/help|Pomoć?]])", |
315 | 315 | 'captcha-addurl' => "Vaše uređivanje sadrži nove vanjske poveznice. Kao zaštitu od automatskog spama, trebate unijeti slova koja vidite na slici: <br />([[Posebno:Captcha/help|Pomoć?]])", |
316 | 316 | 'captcha-create' => "Vaše uređivanje sadrži nove vanjske poveznice. Kao zaštitu od automatskog spama, trebate unijeti slova koja vidite na slici: <br />([[Posebno:Captcha/help|Pomoć?]])", |
— | — | @@ -318,7 +318,7 @@ |
319 | 319 | 'captcha-createaccount' => "Kao zaštitu od automatskog spama, pri otvaranju računa trebate unijeti slova koja vidite na slici: <br />([[Posebno:Captcha/help|Pomoć]])", |
320 | 320 | 'captcha-createaccount-fail' => "Potvrdni kod je nepotpun ili netočan.", |
321 | 321 | ); |
322 | | -$wgConfirmEditMessages['hsb'] = array( |
| 322 | +$messages['hsb'] = array( |
323 | 323 | 'captcha-edit' => 'W twojej změnje su nowe eksterne wotkazy. Jako škitna naprawa přećiwo spamej dyrbiš slědowacy nadawk wuličeć a wuslědk do kašćika zapisować. Klikń potom znowa na „Składować”.<br /> [[{{ns:special}}:Captcha/help|(Čehodla?)]]', |
324 | 324 | 'captcha-addurl' => 'W twojej změnje su nowe eksterne wotkazy. Jako škitna naprawa přećiwo spamej dyrbiš slědowacy nadawk wuličeć a wuslědk do kašćika zapisować. Klikń potom znowa na „Składować”.<br /> [[{{ns:special}}:Captcha/help|(Čehodla?)]]', |
325 | 325 | 'captcha-badlogin' => 'Zo by so awtomatiskemu zadobywanju do hesłow zadźěwało, dyrbiš slědowacy nadawk wuličeć a wuslědk do kašćika zapisować. [[{{ns:special}}:Captcha/help|(Prašenja abo problemy?)]]', |
— | — | @@ -335,7 +335,7 @@ |
336 | 336 | |
337 | 337 | #</pre> <!-- leave this line exactly as it is -->', |
338 | 338 | ); |
339 | | -$wgConfirmEditMessages['id'] = array( |
| 339 | +$messages['id'] = array( |
340 | 340 | 'captcha-edit' => "Suntingan Anda menyertakan pralana luar baru. Sebagai perlindungan terhadap ''spam'' otomatis, Anda harus mengetikkan kata atau hasil perhitungan yang tertera berikut ini:<br /> |
341 | 341 | ([[Special:Captcha/help|info lengkap]])", |
342 | 342 | 'captcha-addurl' => "Suntingan Anda menyertakan pralana luar baru. Sebagai perlindungan terhadap ''spam'' otomatis, Anda harus mengetikkan kata atau hasil perhitungan yang tertera berikut ini:<br /> |
— | — | @@ -356,7 +356,7 @@ |
357 | 357 | ([[Special:Captcha/help|info lengkap]])", |
358 | 358 | 'captcha-createaccount-fail' => "Kode konfirmasi salah atau belum diisi.", |
359 | 359 | ); |
360 | | -$wgConfirmEditMessages['is'] = array( |
| 360 | +$messages['is'] = array( |
361 | 361 | 'captcha-edit' => "Breyting þín fól í sér nýja tengla á aðrar vefsíður. Til þess að verjast sjálfvirku auglýsingarusli verðum við að biðja þig um að skrifa inn orðin sem sjást á þessari mynd: <br />([[Special:Captcha/help|Hvað er þetta?]])", |
362 | 362 | 'captcha-addurl' => "Breyting þín fól í sér nýja tengla á aðrar vefsíður. Til þess að verjast sjálfvirku auglýsingarusli verðum við að biðja þig um að skrifa inn orðin sem sjást á þessari mynd: <br />([[Special:Captcha/help|Hvað er þetta?]])", |
363 | 363 | 'captcha-create' => "Breyting þín fól í sér nýja tengla á aðrar vefsíður. Til þess að verjast sjálfvirku auglýsingarusli verðum við að biðja þig um að skrifa inn orðin sem sjást á þessari mynd: <br />([[Special:Captcha/help|Hvað er þetta?]])", |
— | — | @@ -371,7 +371,7 @@ |
372 | 372 | 'captcha-createaccount' => "Til þess að verjast sjálfvirku auglýsingarusli verðum við að biðja þig um að skrifa inn orðin sem sjást á þessari mynd áður en þú skráir notandanafn: <br />([[Special:Captcha/help|Hvað er þetta?]])", |
373 | 373 | 'captcha-createaccount-fail' => "Staðfestingarkóðinn var rangur eða ekki til staðar.", |
374 | 374 | ); |
375 | | -$wgConfirmEditMessages['it'] = array( |
| 375 | +$messages['it'] = array( |
376 | 376 | 'captcha-edit' => 'La modifica richiesta aggiunge dei nuovi collegamenti (URL) alla pagina; come misura precauzionale contro l\'inserimento automatico di spam, per confermarla è necessario inserire le parole che appaiono nell\'immagine:<br /> |
377 | 377 | ([[Special:Captcha/help|Cosa vuol dire?]])', |
378 | 378 | 'captcha-addurl' => 'La modifica richiesta aggiunge dei nuovi collegamenti (URL) alla pagina; come misura precauzionale contro l\'inserimento automatico di spam, per confermarla è necessario inserire le parole che appaiono nell\'immagine:<br /> |
— | — | @@ -393,7 +393,7 @@ |
394 | 394 | Fare clic sul pulsante \'back\' del browser per tornare alla pagina di modifica.', |
395 | 395 | ); |
396 | 396 | |
397 | | -$wgConfirmEditMessages['ja'] = array( |
| 397 | +$messages['ja'] = array( |
398 | 398 | 'captcha-edit' => 'このページを編集するには下記に現れる数式の答えを入力してください。<br /> |
399 | 399 | ([[Special:Captcha/help|詳細]])', |
400 | 400 | 'captcha-addurl' => 'あなたの編集には新たに外部リンクが追加されています。スパム防止のため、下記の数式の答えを入力してください<br /> |
— | — | @@ -416,7 +416,7 @@ |
417 | 417 | 編集ページに戻るには、ブラウザの戻るボタンを押してください。', |
418 | 418 | ); |
419 | 419 | |
420 | | -$wgConfirmEditMessages['kk-kz'] = array( |
| 420 | +$messages['kk-kz'] = array( |
421 | 421 | 'captcha-edit' => 'Бұл бетті өңдеу үшін, төмендегі қосындылауды шешіңіз де, нәтижесін |
422 | 422 | аумаққа енгізіңіз ([[{{ns:special}}:Captcha/help|көбірек ақпарат]]):', |
423 | 423 | 'captcha-addurl' => 'Түзетуіңізде жаңа сыртқы сілтемелер бар екен. Өздіктік «спам» жасалуынан қорғану үшін, |
— | — | @@ -440,7 +440,7 @@ |
441 | 441 | |
442 | 442 | Бет өңдеуіне қайту бару үшін «Артқа» деген түймесін басыңыз." |
443 | 443 | ); |
444 | | -$wgConfirmEditMessages['kk-tr'] = array( |
| 444 | +$messages['kk-tr'] = array( |
445 | 445 | 'captcha-edit' => 'Bul betti öñdew üşin, tömendegi qosındılawdı şeşiñiz de, nätïjesin |
446 | 446 | awmaqqa engiziñiz ([[{{ns:special}}:Captcha/help|köbirek aqparat]]):', |
447 | 447 | 'captcha-addurl' => 'Tüzetwiñizde jaña sırtqı siltemeler bar eken. Özdiktik «spam» jasalwınan qorğanw üşin, |
— | — | @@ -464,7 +464,7 @@ |
465 | 465 | |
466 | 466 | Bet öñdewine qaýtw barw üşin «Artqa» degen tüýmesin basıñız." |
467 | 467 | ); |
468 | | -$wgConfirmEditMessages['kk-cn'] = array( |
| 468 | +$messages['kk-cn'] = array( |
469 | 469 | 'captcha-edit' => 'بۇل بەتتٸ ٶڭدەۋ ٷشٸن, تٶمەندەگٸ قوسىندىلاۋدى شەشٸڭٸز دە, نٵتيجەسٸن |
470 | 470 | اۋماققا ەنگٸزٸڭٸز ([[{{ns:special}}:Captcha/help|كٶبٸرەك اقپارات]]):', |
471 | 471 | 'captcha-addurl' => 'تٷزەتۋٸڭٸزدە جاڭا سىرتقى سٸلتەمەلەر بار ەكەن. ٶزدٸكتٸك «سپام» جاسالۋىنان قورعانۋ ٷشٸن, |
— | — | @@ -488,11 +488,11 @@ |
489 | 489 | |
490 | 490 | بەت ٶڭدەۋٸنە قايتۋ بارۋ ٷشٸن «ارتقا» دەگەن تٷيمەسٸن باسىڭىز." |
491 | 491 | ); |
492 | | -$wgConfirmEditMessages['kk'] = $wgConfirmEditMessages['kk-kz']; |
493 | | -$wgConfirmEditMessages['ko'] = array( |
| 492 | +$messages['kk'] = $messages['kk-kz']; |
| 493 | +$messages['ko'] = array( |
494 | 494 | 'captcha-createaccount' => '자동 가입을 막기 위해, 아래 문제의 답을 적어야만 가입이 가능합니다([[Special:Captcha/help|관련 도움말]]):', |
495 | 495 | ); |
496 | | -$wgConfirmEditMessages['la'] = array( |
| 496 | +$messages['la'] = array( |
497 | 497 | 'captcha-edit' => 'Ad hanc paginam recensendum, necesse est tibi solvere calculationem subter et responsum in capsam inscribere ([[Special:Captcha/help|Quidst illud?]]):', |
498 | 498 | 'captcha-addurl' => 'Emendatione tua insunt nexus externi; ut spam automaticum vitemus, necesse est tibi solvere calculationem subter et responsum in capsam inscribere ([[Special:Captcha/help|Quidst illud?]]):', |
499 | 499 | 'captcha-badlogin' => 'Ut vitemus ne tesserae frangantur, necesse est tibi solvere calculationem subter et responsum in capsam inscribere ([[Special:Captcha/help|Quidst illud?]]):', |
— | — | @@ -501,14 +501,14 @@ |
502 | 502 | 'captcha-create' => 'Ad paginam creandum, necesse est tibi solvere calculationem subter et responsum in capsam inscribere ([[Special:Captcha/help|Quidst illud?]]):', |
503 | 503 | 'captchahelp-title' => 'Captcha auxilium', |
504 | 504 | ); |
505 | | -$wgConfirmEditMessages['lo'] = array( |
| 505 | +$messages['lo'] = array( |
506 | 506 | 'captcha-edit' => 'ການດັດແກ້ ຂອງ ທ່ານ ມີລິ້ງູຄ໌ພາຍນອກ. ເພື່ອ ເປັນການຊ່ອຍປ້ອງກັນ ສະແປມອັດຕະໂນມັດ, ກະລຸນາແກ້ເລກບວກ ງ່າຍໆຂ້າງລຸ່ມນີ້ ແລ້ວ ພິມຄຳຕອບໃສ່ໃນ ກັບ ([[Special:Captcha/help|more info]]):', |
507 | 507 | 'captcha-addurl' => 'ການດັດແກ້ຂອງທ່ານ ມີ ການກາງລິ້ງຄ໌ຫາພາຍນອກ. ເພື່ອເປັນການຊ່ອຍປ້ອງກັນ ສະແປມອັດຕະໂນມັດ ກະລຸນາ ແກ້ເລກບວກງ່າຍໆຂ້າງລຸ່ມນີ້ ແລ້ວ ພິມຜົນບວກ ໃສ່ ກັບ ([[Special:Captcha/help|ຂໍ້ມູນເພີ່ມເຕີມ]]):', |
508 | 508 | 'captcha-createaccount' => 'ເພື່ອປ້ອງກັນ ການສ້າງບັນຊີແບບອັດຕະໂນມັດ, ກະລຸນາ ແກ້ເລກບວກງ່າຍໆ ຂ້າງລຸ່ມ ແລ້ວ ພິມຄຳຕອບໃສ່ ກັບ ([[Special:Captcha/help|more info]]):', |
509 | 509 | 'captcha-createaccount-fail' => "ບໍ່ຖືກ ຫຼື ບໍ່ມີລະຫັດຢືນຢັນ.", |
510 | 510 | 'captcha-create' => 'ກະລຸນາ ແກ້ເລກບວກງ່າຍໆລຸ່ມນີ້ ແລະ ພິມຜົນບວກໃສ່ໃນກັບ ເພື່ອ ສ້າງໜ້ານີ້ ([[Special:Captcha/help|ຂໍ້ມູນເພີ່ມເຕີມ]]):', |
511 | 511 | ); |
512 | | -$wgConfirmEditMessages['lv'] = array( |
| 512 | +$messages['lv'] = array( |
513 | 513 | 'captcha-edit' => "Tavas izmaiņas ietver jaunu URL saiti. Lai pasargātos no automātiskas mēstuļošanas, Tev ir jāieraksta vārds, kas redzams šajā attēlā: <br />([[Special:Captcha/help|Kāpēc tā?]])", |
514 | 514 | 'captcha-addurl' => "Tavas izmaiņas ietver jaunu URL saiti. Lai pasargātos no automātiskas mēstuļošanas, Tev ir jāieraksta vārds, kas redzams šajā attēlā: <br />([[Special:Captcha/help|Kāpēc tā?]])", |
515 | 515 | 'captcha-create' => "Tavas izmaiņas ietver jaunu URL saiti. Lai pasargātos no automātiskas mēstuļošanas, Tev ir jāieraksta vārds, kas redzams šajā attēlā: <br />([[Special:Captcha/help|Kāpēc tā?]])", |
— | — | @@ -517,12 +517,12 @@ |
518 | 518 | 'captcha-createaccount' => "Lai pasargātos no automātiskas mēstuļošanas, Tev reģistrējoties ir jāieraksta vārds, kas redzams šajā attēlā: <br />([[Special:Captcha/help|Kāpēc tā?]])", |
519 | 519 | 'captcha-createaccount-fail' => "Nepareizs apstiprinājuma kods vai arī tas nav ievadīts.", |
520 | 520 | ); |
521 | | -$wgConfirmEditMessages['nan'] = array( |
| 521 | +$messages['nan'] = array( |
522 | 522 | 'captcha-createaccount' => "Ūi beh ī-hông lâng iōng ke-si chū-tōng chù-chheh koh tah kóng-kò, chhiáⁿ lí kā chhut-hiān tī ang-á lāi-bīn ê jī phah 1 piàn (thang chèng-bêng lí m̄ sī ki-khì-lâng): <br /> |
523 | 523 | ([[Special:Captcha/help|Che sī siáⁿ-hòe?]])", |
524 | 524 | 'captcha-createaccount-fail' => "Khak-jīn-bé chhò-gō· iah-sī làu-kau.", |
525 | 525 | ); |
526 | | -$wgConfirmEditMessages['nds'] = array( |
| 526 | +$messages['nds'] = array( |
527 | 527 | 'captcha-edit' => 'In dien Text steiht en nee Lenk na buten dat Wiki. Dat hier keen automaatsch instellten Spam rinkummt, musst du disse lütte Rekenopgaav lösen ([[Special:Captcha/help|mehr dorto]]):', |
528 | 528 | 'captcha-createaccount' => 'Dat hier nich Brukers automaatsch anleggt warrt, musst du disse lütte Rekenopgaav lösen ([[Special:Captcha/help|mehr dorto]]):', |
529 | 529 | 'captcha-createaccount-fail' => 'Kood to’n Bestätigen is verkehrt oder fehlt.', |
— | — | @@ -539,7 +539,7 @@ |
540 | 540 | |
541 | 541 | #</pre> <!-- leave this line exactly as it is -->', |
542 | 542 | ); |
543 | | -$wgConfirmEditMessages['nl'] = array( |
| 543 | +$messages['nl'] = array( |
544 | 544 | 'captcha-edit' => 'Uw bewerking bevat nieuwe externe links (URL\'s). Voer ter bescherming tegen geautomatiseerde spam de woorden in die in de volgende afbeelding te zien zijn:<br /> |
545 | 545 | ([[Special:Captcha/help|Wat is dit?]])', |
546 | 546 | 'captcha-addurl' => 'Uw bewerking bevat nieuwe externe links (URL\'s). Voer ter bescherming tegen geautomatiseerde spam de woorden in die in de volgende afbeelding te zien zijn:<br /> |
— | — | @@ -565,7 +565,7 @@ |
566 | 566 | # * Iedere niet-lege regel is een fragment van een reguliere expressie die alleen van toepassing is op hosts binnen URL\'s |
567 | 567 | #</pre> <!-- leave this line exactly as it is -->', |
568 | 568 | ); |
569 | | -$wgConfirmEditMessages['no'] = array( |
| 569 | +$messages['no'] = array( |
570 | 570 | 'captcha-edit' => 'For å redigere denne artikkelen, vennligst skriv inn summen nedenfor i boksen ([[Special:Captcha/help|mer informasjon]]):', |
571 | 571 | 'captcha-addurl' => 'Din redigering inneholder nye eksterne lenker. For å hjelpe oss å beskytte oss mot automatisk spam, vennligst skriv inn summen av dette enkle regnestykket i boksen nedenfor ([[Special:Captcha/help|mer informasjon]]):', |
572 | 572 | 'captcha-badlogin' => 'For å hjelpe oss med å beskytte oss mot automatisk passordtyveri, vennligst løs det enkle regnestykket nedenfor og skriv inn svaret i bosken ([[Special:Captcha/help|mer informasjon]]):', |
— | — | @@ -587,7 +587,7 @@ |
588 | 588 | # * Alle linjer som ikke er blanke er fragmenter av regulære uttrykk som sjekker verter i URL-er |
589 | 589 | #</pre> <!-- leave this line exactly as it is -->', |
590 | 590 | ); |
591 | | -$wgConfirmEditMessages['nn'] = array( |
| 591 | +$messages['nn'] = array( |
592 | 592 | 'captcha-edit' => "Endringa di inkluderer nye lenkjer; som eit vern mot automatisert reklame (spam) er du nøydd til skrive inn orda i dette bildet: <br />([[Special:Captcha/help|Kva er dette?]])", |
593 | 593 | 'captcha-addurl' => "Endringa di inkluderer nye lenkjer; som eit vern mot automatisert reklame (spam) er du nøydd til skrive inn orda i dette bildet: <br />([[Special:Captcha/help|Kva er dette?]])", |
594 | 594 | 'captcha-create' => "Endringa di inkluderer nye lenkjer; som eit vern mot automatisert reklame (spam) er du nøydd til skrive inn orda i dette bildet: <br />([[Special:Captcha/help|Kva er dette?]])", |
— | — | @@ -596,7 +596,7 @@ |
597 | 597 | 'captcha-createaccount' => "For å verne Wikipedia mot reklame (spam) må du skrive inn orda i biletet for å registrere ein konto. <br />([[Special:Captcha/help|Kva er dette?]])", |
598 | 598 | 'captcha-createaccount-fail' => "Feil eller manglande godkjenningskode.", |
599 | 599 | ); |
600 | | -$wgConfirmEditMessages['oc'] = array( |
| 600 | +$messages['oc'] = array( |
601 | 601 | 'captcha-edit' => 'Vòstra modificacion inclutz de ligams URL novèla ; per empachar las connexions automatizadas, devètz picar los mots que s’afichan dins l’imatge que seguís : <br />([[Special:Captcha/help|Qu\'es aquò?]])', |
602 | 602 | 'captcha-addurl' => 'Vòstra modificacion inclutz de ligams URL novèla ; per empachar las connexions automatizadas, devètz picar los mots que s’afichan dins l’imatge que seguís : <br />([[Special:Captcha/help|Qu\'es aquò?]])', |
603 | 603 | 'captcha-badlogin' => 'Per ensajar de contornar las temptativas de cracatge de senhals automatizadas per de robòts, recopiatz lo tèxt çai jos dins la boîta de tèxt plaçada al dejos d\'aqueste. ([[Special:Captcha/help|Mai d’entre-senhas]])', |
— | — | @@ -608,7 +608,7 @@ |
609 | 609 | 'captchahelp-cookies-needed' => 'Devètz aver los cookies activats dins vòstre navegaire per qu\'aquò foncione.', |
610 | 610 | 'captchahelp-text' => 'Los sites webs que permeton al mai grand nombre de participar, coma aqueste wiki, son sovent atacats per de spammers qu\'utilizan d\'espleches automatizas per mandar lor ligams sus de fòrça sites sulcòp. Son fòrt aisits de suprimir mas avèm francament de causas mai risolièras de far. De còps quand ajustatz de ligams novèls vèrs lo web, lo wiki pòt vos mostrar un imatge amb un tèxt coloriat o torçut e vos demandar de lo picar. Es una tasca relativament complicada d\'automatizar, çò que permet de diferenciar un uman real d\'un logicial automatic malvolent. Malaürosament, aqueste sistèma es pas adaptat a d\'utilizaires mal-vesents o utilizant de navigaires textuals o audiò. Actualament, prepausem pas d\'alternativas adaptadas. Se avètz besonh d\'ajuda esitetz pas a contactar los administrators del sit. Clicatz sul boton \'precedent\' de vòstre navegaire per tornar a l\'editor.', |
611 | 611 | ); |
612 | | -$wgConfirmEditMessages['pl'] = array( |
| 612 | +$messages['pl'] = array( |
613 | 613 | 'captcha-edit' => 'Aby edytować tę stronę musisz rozwiązać proste działanie matematyczne poniżej i wpisać wynik do pola tekstowego ([[Special:Captcha/help|wyjaśnienie]]):', |
614 | 614 | 'captcha-addurl' => 'Twoja edycja zawiera nowe linki zewnętrzne. Ze względu na ochronę przed zautomatyzowanym spamem prosimy wykonać proste działanie matematyczne i wpisać wynik w pole tekstowe ([[Special:Captcha/help|więcej informacji]]):', |
615 | 615 | 'captcha-badlogin' => 'Ze względu na zabezpieczenie przed automatycznym łamaniem haseł prosimy o rozwiązanie tego prostego zadania i wpisanie odwiedzi w pole obok ([[Special:Captcha/help|więcej informacji]])', |
— | — | @@ -624,7 +624,7 @@ |
625 | 625 | # * Każda linia, która nie jest pusta, jest fragmentem wyrażenia regularnego, które ma pasować do adresów wewnątrz adresów URL |
626 | 626 | #</pre> <!-- zostaw tę linię dokładnie jak jest -->', |
627 | 627 | ); |
628 | | -$wgConfirmEditMessages['pms'] = array( |
| 628 | +$messages['pms'] = array( |
629 | 629 | 'captcha-edit' => 'Për fe-ie dle modìfiche ansima a st\'artìcol-sì, për piasì ch\'a fasa ël total ambelessì sota |
630 | 630 | e ch\'a buta l\'arzulta ant ël quadrèt ([[Special:Captcha/help|për savejne dë pì]]):', |
631 | 631 | 'captcha-addurl' => 'Soa modìfica a la gionta dj\'anliure esterne. Për giutene a vardesse da la reclam aotomatisà, për piasì ch\'a fasa ël total ambelessì sota e ch\'a buta l\'arzultà ant ël quadrèt ([[Special:Captcha/help|për savejne dë pì]]):', |
— | — | @@ -649,7 +649,7 @@ |
650 | 650 | # * minca riga nen veujda a l\'é un frament d\'espression regolar ch\'as dòvra për identifiché j\'adrësse dle màchine servente ant j\'anliure |
651 | 651 | #</pre> <!-- leave this line exactly as it is -->', |
652 | 652 | ); |
653 | | -$wgConfirmEditMessages['pt'] = array( |
| 653 | +$messages['pt'] = array( |
654 | 654 | 'captcha-edit' => 'Para editar esta página será necessário que você digite as palavras exibidas na seguinte imagem no box apropriado ([[Special:Captcha/help|o que é isto?]])', |
655 | 655 | 'captcha-addurl' => 'Sua edição inclui novas ligações externas; como prevenção contra sistemas automatizados que inserem spam, será necessário que você digite as palavras exibidas na seguinte imagem no box apropriado ([[Special:Captcha/help|o que é isto?]])', |
656 | 656 | 'captcha-badlogin' => 'Como prevenção contra formas automatizadas de pesquisa e descoberta de senhas, será necessário que você digite as palavras exibidas na seguinte imagem no box apropriado ([[Special:Captcha/help|o que é isto?]])', |
— | — | @@ -672,8 +672,8 @@ |
673 | 673 | # * Todas as linhas que não estiverem em branco são um fragmento de regex, as quais referem-se aos apenas através de URLs; |
674 | 674 | #</pre> <!-- mantenha esta linha exatamente desta forma -->', |
675 | 675 | ); |
676 | | -$wgConfirmEditMessages['pt-br'] = $wgConfirmEditMessages['pt']; |
677 | | -$wgConfirmEditMessages['ro'] = array( |
| 676 | +$messages['pt-br'] = $messages['pt']; |
| 677 | +$messages['ro'] = array( |
678 | 678 | 'captcha-edit' => 'Editarea include legături externe noi. Pentru a evita spam-ul automat, vă rugăm să rezolvaţi adunarea de mai jos şi introduceţi rezultatul în căsuţă ([[Special:Captcha/help|detalii]]):', |
679 | 679 | 'captcha-addurl' => 'Editarea include legături externe noi. Pentru a evita spam-ul automat, vă rugăm să rezolvaţi adunarea de mai jos şi introduceţi rezultatul în căsuţă ([[Special:Captcha/help|detalii]]):', |
680 | 680 | 'captcha-badlogin' => 'Ca măsură de protecţie împotriva spargerii de parole, vă rugăm să rezolvaţi adunarea de mai jos şi introduceţi rezultatul în căsuţă ([[Special:Captcha/help|detalii]]):', |
— | — | @@ -690,7 +690,7 @@ |
691 | 691 | |
692 | 692 | Va fi nevoie ca browserul folosit să suporte module cookie.', |
693 | 693 | ); |
694 | | -$wgConfirmEditMessages['ru'] = array( |
| 694 | +$messages['ru'] = array( |
695 | 695 | 'captcha-edit' => "Вы добавили ссылку на внешний сайт; в целях защиты от автоматического спама, введите буквы изображённые на картинке:<br /> |
696 | 696 | ([[{{ns:special}}:Captcha/help|Что это такое?]])", |
697 | 697 | 'captcha-addurl' => "Вы добавили ссылку на внешний сайт; в целях защиты от автоматического спама, введите буквы изображённые на картинке:<br /> |
— | — | @@ -709,7 +709,7 @@ |
710 | 710 | ([[{{ns:special}}:Captcha/help|Что это такое?]])", |
711 | 711 | 'captcha-createaccount-fail' => "Код подтверждения отсутствует или неверен.", |
712 | 712 | ); |
713 | | -$wgConfirmEditMessages['sk'] = array( |
| 713 | +$messages['sk'] = array( |
714 | 714 | 'captcha-edit' => 'Vaša úprava obsahuje nové externé odkazy. Ako pomoc pri ochrane pred automatickým spamom vyriešte prosím tento jednoduchý súčet a zadajte výsledok do poľa ([[Special:Captcha/help|viac informácií]]):', |
715 | 715 | 'captcha-addurl' => 'Vaša úprava obsahuje nové externé odkazy. Ako pomoc pri ochrane pred automatickým spamom vyriešte prosím tento jednoduchý súčet a zadajte výsledok do poľa ([[Special:Captcha/help|viac informácií]]):', |
716 | 716 | 'captcha-badlogin' => 'Ako ochranu proti automatizovanému lámaniu hesiel, prosím vyriešte nasledujúci súčet a zadajte ho do poľa pre odpoveď ([[Special:Captcha/help|viac informácií]]):', |
— | — | @@ -733,7 +733,7 @@ |
734 | 734 | #</pre> <!-- leave this line exactly as it is -->', |
735 | 735 | ); |
736 | 736 | |
737 | | -$wgConfirmEditMessages['sl'] = array( |
| 737 | +$messages['sl'] = array( |
738 | 738 | 'captcha-edit' => "Vaše urejanje vključuje nove URL-povezave; zaradi zaščite pred avtomatizirano navlako boste morali vpisati besede, ki se pojavijo v okencu: <br />([[{{ns:Special}}:Captcha/help|Kaj je to?]])", |
739 | 739 | 'captcha-addurl' => "Vaše urejanje vključuje nove URL-povezave; zaradi zaščite pred avtomatizirano navlako boste morali vpisati besede, ki se pojavijo v okencu: <br />([[{{ns:Special}}:Captcha/help|Kaj je to?]])", |
740 | 740 | 'captcha-create' => "Vaše urejanje vključuje nove URL-povezave; zaradi zaščite pred avtomatizirano navlako boste morali vpisati besede, ki se pojavijo v okencu: <br />([[{{ns:Special}}:Captcha/help|Kaj je to?]])", |
— | — | @@ -748,7 +748,7 @@ |
749 | 749 | 'captcha-createaccount' => "Za registracijo je zaradi zaščite pred neželenimi reklamnimi sporočili treba vpisati prikazane besede: <br />([[{{ns:special}}:Captcha|Kaj je to?]])", |
750 | 750 | 'captcha-createaccount-fail' => "Nepravilna ali manjkajoča potrditvena koda.", |
751 | 751 | ); |
752 | | -$wgConfirmEditMessages['sq'] = array( |
| 752 | +$messages['sq'] = array( |
753 | 753 | 'captcha-edit' => 'Redaktimi juaj ka lidhje URL të reja dhe si mbrojtje kundër abuzimeve automatike duhet të shtypni çfarë shfaqet tek figura e mëposhtme:<br /> ([[Special:Captcha|Çfarë është kjo?]])', |
754 | 754 | 'captcha-addurl' => 'Redaktimi juaj ka lidhje URL të reja dhe si mbrojtje kundër abuzimeve automatike duhet të shtypni çfarë shfaqet tek figura e mëposhtme:<br /> ([[Special:Captcha|Çfarë është kjo?]])', |
755 | 755 | 'captcha-create' => 'Redaktimi juaj ka lidhje URL të reja dhe si mbrojtje kundër abuzimeve automatike duhet të shtypni çfarë shfaqet tek figura e mëposhtme:<br /> ([[Special:Captcha|Çfarë është kjo?]])', |
— | — | @@ -764,7 +764,7 @@ |
765 | 765 | 'captcha-createaccount-fail' => 'Mesazhi që duhej shtypur mungon ose nuk është shtypur siç duhet.', |
766 | 766 | ); |
767 | 767 | |
768 | | -$wgConfirmEditMessages['su'] = array( |
| 768 | +$messages['su'] = array( |
769 | 769 | 'captcha-edit' => 'Pikeun ngédit artikel ieu, mangga eusian itungan di handap ieu ([[Special:Captcha/help|émbaran lengkep]]):', |
770 | 770 | 'captcha-addurl' => 'Éditan anjeun ngawengku tumbu kaluar anyar. Pikeun nyegah spam, mangga eusian itungan di handap ieu [[Special:Captcha/help|émbaran lengkep]]):', |
771 | 771 | 'captcha-createaccount' => 'Pikeun nyegah dijieunna rekening sacara otomatis, mangga eusian itungan di handap ieu ([[Special:Captcha/help|émbaran lengkep]]):', |
— | — | @@ -782,7 +782,7 @@ |
783 | 783 | Hit the \'back\' button in your browser to return to the page editor.', |
784 | 784 | ); |
785 | 785 | |
786 | | -$wgConfirmEditMessages['sv'] = array( |
| 786 | +$messages['sv'] = array( |
787 | 787 | 'captcha-edit' => 'För att redigera den här sidan måste du först skriva svaret på följande |
788 | 788 | räkneuppgift i rutan ([[Special:Captcha/help|mer information]]):', |
789 | 789 | 'captcha-addurl' => 'Din ändring lägger till nya externa länkar i texten. För att skydda wikin mot |
— | — | @@ -817,7 +817,7 @@ |
818 | 818 | #</pre> <!-- leave this line exactly as it is -->', |
819 | 819 | ); |
820 | 820 | |
821 | | -$wgConfirmEditMessages['uk'] = array( |
| 821 | +$messages['uk'] = array( |
822 | 822 | 'captchahelp-text' => "Вікіпедія застосовує техніку розрізнення людей від комп'ютерів, яка використовує розпізнавання образів, для захисту від комп'ютерних шкідливих програм, які автоматично реєструються (найчастіше спамлять у статтях). |
823 | 823 | |
824 | 824 | Для реєстрації у Вікіпедії та іноді й при редагуванні статей користувачеві потрібно ввести вказану контрольну послідовність символів, і яку вони, будучи людьми, а не комп'ютерними програмами, можуть легко розпізнати. |
— | — | @@ -827,7 +827,7 @@ |
828 | 828 | Hit the 'back' button in your browser to return to the page editor.", |
829 | 829 | 'captcha-createaccount-fail' => 'Невірний або відсутній код підтвердження.', |
830 | 830 | ); |
831 | | -$wgConfirmEditMessages['wa'] = array( |
| 831 | +$messages['wa'] = array( |
832 | 832 | 'captcha-edit' => 'Dins vos candjmints i gn a des novelès hårdêyes (URL); po s\' mete a houte des robots di spam, nos vs dimandans d\' acertiner ki vos estoz bén ene djin, po çoula, tapez les mots k\' aparexhèt dins l\' imådje chal pa dzo:<br />([[{{ns:special}}:Captcha/help|Pocwè fjhans ns çoula?]])', |
833 | 833 | 'captcha-addurl' => 'Dins vos candjmints i gn a des novelès hårdêyes (URL); po s\' mete a houte des robots di spam, nos vs dimandans d\' acertiner ki vos estoz bén ene djin, po çoula, tapez les mots k\' aparexhèt dins l\' imådje chal pa dzo:<br />([[{{ns:special}}:Captcha/help|Pocwè fjhans ns çoula?]])', |
834 | 834 | 'captcha-create' => 'Dins vos candjmints i gn a des novelès hårdêyes (URL); po s\' mete a houte des robots di spam, nos vs dimandans d\' acertiner ki vos estoz bén ene djin, po çoula, tapez les mots k\' aparexhèt dins l\' imådje chal pa dzo:<br />([[{{ns:special}}:Captcha/help|Pocwè fjhans ns çoula?]])', |
— | — | @@ -843,7 +843,7 @@ |
844 | 844 | 'captcha-createaccount' => 'Po s\' mete a houte des robots di spam, nos vs dimandans d\' acertiner ki vos estoz bén ene djin po-z ahiver vosse conte, po çoula, tapez les mots k\' aparexhèt dins l\' imådje chal pa dzo:<br />([[{{ns:special}}:Captcha/help|Pocwè fjhans ns çoula?]])', |
845 | 845 | 'captcha-createaccount-fail' => 'Li côde d\' acertinaedje est incorek ou mancant.', |
846 | 846 | ); |
847 | | -$wgConfirmEditMessages['yue'] = array( |
| 847 | +$messages['yue'] = array( |
848 | 848 | 'captcha-edit' => "你編輯的內容中含有新的URL連結;為咗避免受到自動垃圾程式的侵擾,你需要輸入顯示喺下面圖片度嘅文字:<br /> |
849 | 849 | ([[Special:Captcha/help|呢個係乜嘢嚟?]])", |
850 | 850 | 'captcha-addurl' => "你編輯的內容中含有新的URL連結;為咗避免受到自動垃圾程式的侵擾,你需要輸入顯示喺下面圖片度嘅文字:<br /> |
— | — | @@ -870,7 +870,7 @@ |
871 | 871 | # * 所有非空白行係一個regex部份,只係會同裏面嘅URL主機相符 |
872 | 872 | #</pre> <!-- leave this line exactly as it is -->', |
873 | 873 | ); |
874 | | -$wgConfirmEditMessages['zh-hans'] = array( |
| 874 | +$messages['zh-hans'] = array( |
875 | 875 | 'captcha-edit' => "你编辑的内容中含有一个新的URL链接;为了免受自动垃圾程序的侵扰,你需要输入显示在下面图片中的文字:<br /> |
876 | 876 | ([[Special:Captcha/help|这是什么?]])", |
877 | 877 | 'captcha-addurl' => "你编辑的内容中含有一个新的URL链接;为了免受自动垃圾程序的侵扰,你需要输入显示在下面图片中的文字:<br /> |
— | — | @@ -897,7 +897,7 @@ |
898 | 898 | # * 所有非空白行是一个regex部份,只是跟在里面的URL主机相符 |
899 | 899 | #</pre> <!-- leave this line exactly as it is -->', |
900 | 900 | ); |
901 | | -$wgConfirmEditMessages['zh-hant'] = array( |
| 901 | +$messages['zh-hant'] = array( |
902 | 902 | 'captcha-edit' => "你編輯的內容中含有一個新的URL連結;為了免受自動垃圾程式的侵擾,你需要輸入顯示在下面圖片中的文字:<br /> |
903 | 903 | ([[Special:Captcha/help|這是什麼?]])", |
904 | 904 | 'captcha-addurl' => "你編輯的內容中含有一個新的URL連結;為了免受自動垃圾程式的侵擾,你需要輸入顯示在下面圖片中的文字:<br /> |
— | — | @@ -924,10 +924,10 @@ |
925 | 925 | # * 所有非空白行是一個regex部份,只是跟在裏面的URL主機相符 |
926 | 926 | #</pre> <!-- leave this line exactly as it is -->', |
927 | 927 | ); |
928 | | -$wgConfirmEditMessages['zh'] = $wgConfirmEditMessages['zh-hans']; |
929 | | -$wgConfirmEditMessages['zh-cn'] = $wgConfirmEditMessages['zh-hans']; |
930 | | -$wgConfirmEditMessages['zh-hk'] = $wgConfirmEditMessages['zh-hant']; |
931 | | -$wgConfirmEditMessages['zh-min-nan'] = $wgConfirmEditMessages['nan']; |
932 | | -$wgConfirmEditMessages['zh-sg'] = $wgConfirmEditMessages['zh-hans']; |
933 | | -$wgConfirmEditMessages['zh-tw'] = $wgConfirmEditMessages['zh-hant']; |
934 | | -$wgConfirmEditMessages['zh-yue'] = $wgConfirmEditMessages['yue']; |
| 928 | +$messages['zh'] = $messages['zh-hans']; |
| 929 | +$messages['zh-cn'] = $messages['zh-hans']; |
| 930 | +$messages['zh-hk'] = $messages['zh-hant']; |
| 931 | +$messages['zh-min-nan'] = $messages['nan']; |
| 932 | +$messages['zh-sg'] = $messages['zh-hans']; |
| 933 | +$messages['zh-tw'] = $messages['zh-hant']; |
| 934 | +$messages['zh-yue'] = $messages['yue']; |
Index: trunk/extensions/ConfirmEdit/MathCaptcha.class.php |
— | — | @@ -0,0 +1,40 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class MathCaptcha extends SimpleCaptcha { |
| 5 | + |
| 6 | + /** Validate a captcha response */ |
| 7 | + function keyMatch( $req, $info ) { |
| 8 | + return (int)$req->getVal( 'wpCaptchaAnswer' ) == (int)$info['answer']; |
| 9 | + } |
| 10 | + |
| 11 | + /** Produce a nice little form */ |
| 12 | + function getForm() { |
| 13 | + list( $sum, $answer ) = $this->pickSum(); |
| 14 | + $index = $this->storeCaptcha( array( 'answer' => $answer ) ); |
| 15 | + |
| 16 | + $form = '<table><tr><td>' . $this->fetchMath( $sum ) . '</td>'; |
| 17 | + $form .= '<td>' . wfInput( 'wpCaptchaAnswer', false, false, array( 'tabindex' => '1' ) ) . '</td></tr></table>'; |
| 18 | + $form .= wfHidden( 'wpCaptchaId', $index ); |
| 19 | + return $form; |
| 20 | + } |
| 21 | + |
| 22 | + /** Pick a random sum */ |
| 23 | + function pickSum() { |
| 24 | + $a = mt_rand( 0, 100 ); |
| 25 | + $b = mt_rand( 0, 10 ); |
| 26 | + $op = mt_rand( 0, 1 ) ? '+' : '-'; |
| 27 | + $sum = "{$a} {$op} {$b} = "; |
| 28 | + $ans = $op == '+' ? ( $a + $b ) : ( $a - $b ); |
| 29 | + return array( $sum, $ans ); |
| 30 | + } |
| 31 | + |
| 32 | + /** Fetch the math */ |
| 33 | + function fetchMath( $sum ) { |
| 34 | + $math = new MathRenderer( $sum ); |
| 35 | + $math->setOutputMode( MW_MATH_PNG ); |
| 36 | + $html = $math->render(); |
| 37 | + return preg_replace( '/alt=".*"/', '', $html ); |
| 38 | + } |
| 39 | + |
| 40 | +} |
| 41 | +?> |
Property changes on: trunk/extensions/ConfirmEdit/MathCaptcha.class.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 42 | + native |
Index: trunk/extensions/ConfirmEdit/FancyCaptcha.i18n.php |
— | — | @@ -5,10 +5,8 @@ |
6 | 6 | * |
7 | 7 | * @addtogroup Extensions |
8 | 8 | */ |
| 9 | +$messages = array( |
9 | 10 | |
10 | | -function efFancyCaptchaMessages() { |
11 | | - $messages = array( |
12 | | - |
13 | 11 | /* English */ |
14 | 12 | 'en' => array( |
15 | 13 | 'fancycaptcha-addurl' => 'Your edit includes new external links. To help protect against automated |
— | — | @@ -350,18 +348,16 @@ |
351 | 349 | 'fancycaptcha-edit' => '如您想要編輯此頁面,請輸入以下的文字([[Special:Captcha/help|相關資訊]]):', |
352 | 350 | ), |
353 | 351 | |
354 | | - ); |
| 352 | +); |
355 | 353 | |
356 | | - /* Kazakh default, fallback to kk-kz */ |
357 | | - $messages['kk'] = $messages['kk-kz']; |
358 | | - /* Chinese defaults, fallback to zh-hans or zh-hant */ |
359 | | - $messages['zh'] = $messages['zh-hans']; |
360 | | - $messages['zh-cn'] = $messages['zh-hans']; |
361 | | - $messages['zh-hk'] = $messages['zh-hant']; |
362 | | - $messages['zh-tw'] = $messages['zh-hans']; |
363 | | - $messages['zh-sg'] = $messages['zh-hant']; |
364 | | - /* Cantonese default, fallback to yue */ |
365 | | - $messages['zh-yue'] = $messages['yue']; |
| 354 | +/* Kazakh default, fallback to kk-kz */ |
| 355 | +$messages['kk'] = $messages['kk-kz']; |
| 356 | +/* Chinese defaults, fallback to zh-hans or zh-hant */ |
| 357 | +$messages['zh'] = $messages['zh-hans']; |
| 358 | +$messages['zh-cn'] = $messages['zh-hans']; |
| 359 | +$messages['zh-hk'] = $messages['zh-hant']; |
| 360 | +$messages['zh-tw'] = $messages['zh-hans']; |
| 361 | +$messages['zh-sg'] = $messages['zh-hant']; |
| 362 | +/* Cantonese default, fallback to yue */ |
| 363 | +$messages['zh-yue'] = $messages['yue']; |
366 | 364 | |
367 | | - return $messages; |
368 | | -} |
Index: trunk/extensions/ConfirmEdit/ConfirmEdit.php |
— | — | @@ -27,11 +27,13 @@ |
28 | 28 | * @addtogroup Extensions |
29 | 29 | */ |
30 | 30 | |
31 | | -if ( defined( 'MEDIAWIKI' ) ) { |
| 31 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 32 | + exit; |
| 33 | +} |
32 | 34 | |
33 | 35 | global $wgExtensionFunctions, $wgGroupPermissions; |
34 | 36 | |
35 | | -$wgExtensionFunctions[] = 'ceSetup'; |
| 37 | +$wgExtensionFunctions[] = 'confirmEditSetup'; |
36 | 38 | $wgExtensionCredits['other'][] = array( |
37 | 39 | 'name' => 'ConfirmEdit', |
38 | 40 | 'author' => 'Brion Vibber', |
— | — | @@ -39,9 +41,6 @@ |
40 | 42 | 'description' => 'Simple captcha implementation', |
41 | 43 | ); |
42 | 44 | |
43 | | -# Internationalisation file |
44 | | -require_once( 'ConfirmEdit.i18n.php' ); |
45 | | - |
46 | 45 | /** |
47 | 46 | * The 'skipcaptcha' permission key can be given out to |
48 | 47 | * let known-good users perform triggering actions without |
— | — | @@ -167,29 +166,33 @@ |
168 | 167 | |
169 | 168 | /** Register special page */ |
170 | 169 | global $wgSpecialPages; |
171 | | -$wgSpecialPages['Captcha'] = array( /*class*/ 'SpecialPage', /*name*/'Captcha', /*restriction*/ '', |
172 | | - /*listed*/ false, /*function*/ false, /*file*/ false ); |
| 170 | +$wgSpecialPages['Captcha'] = array( /*class*/'CaptchaSpecialPage', /*name*/'Captcha' ); |
173 | 171 | |
174 | | -/** |
175 | | - * Set up message strings for captcha utilities. |
176 | | - */ |
177 | | -function ceSetup() { |
178 | | - # Add messages |
179 | | - global $wgMessageCache, $wgConfirmEditMessages; |
180 | | - foreach( $wgConfirmEditMessages as $lang => $messages ) |
181 | | - $wgMessageCache->addMessages( $messages, $lang ); |
| 172 | +$wgConfirmEditIP = dirname( __FILE__ ); |
| 173 | +$wgExtensionMessagesFiles['ConfirmEdit'] = "$wgConfirmEditIP/ConfirmEdit.i18n.php"; |
182 | 174 | |
183 | | - global $wgHooks, $wgCaptcha, $wgCaptchaClass; |
184 | | - $wgCaptcha = new $wgCaptchaClass(); |
185 | | - $wgHooks['EditFilter'][] = array( &$wgCaptcha, 'confirmEdit' ); |
| 175 | +if ( defined( 'MW_SUPPORTS_EDITFILTERMERGED' ) ) { |
| 176 | + $wgHooks['EditFilterMerged'][] = 'ConfirmEditHooks::confirmEditMerged'; |
| 177 | +} else { |
| 178 | + $wgHooks['EditFilter'][] = 'ConfirmEditHooks::confirmEdit'; |
| 179 | +} |
| 180 | +$wgHooks['UserCreateForm'][] = 'ConfirmEditHooks::injectUserCreate'; |
| 181 | +$wgHooks['AbortNewAccount'][] = 'ConfirmEditHooks::confirmUserCreate'; |
| 182 | +$wgHooks['LoginAuthenticateAudit'][] = 'ConfirmEditHooks::triggerUserLogin'; |
| 183 | +$wgHooks['UserLoginForm'][] = 'ConfirmEditHooks::injectUserLogin'; |
| 184 | +$wgHooks['AbortLogin'][] = 'ConfirmEditHooks::confirmUserLogin'; |
186 | 185 | |
187 | | - $wgHooks['UserCreateForm'][] = array( &$wgCaptcha, 'injectUserCreate' ); |
188 | | - $wgHooks['AbortNewAccount'][] = array( &$wgCaptcha, 'confirmUserCreate' ); |
189 | | - |
190 | | - $wgHooks['LoginAuthenticateAudit'][] = array( &$wgCaptcha, 'triggerUserLogin' ); |
191 | | - $wgHooks['UserLoginForm'][] = array( &$wgCaptcha, 'injectUserLogin' ); |
192 | | - $wgHooks['AbortLogin'][] = array( &$wgCaptcha, 'confirmUserLogin' ); |
193 | | - |
| 186 | +$wgAutoloadClasses['ConfirmEditHooks'] |
| 187 | + = $wgAutoloadClasses['SimpleCaptcha'] |
| 188 | + = $wgAutoloadClasses['CaptchaSessionStore'] |
| 189 | + = $wgAutoloadClasses['CaptchaCacheStore'] |
| 190 | + = $wgAutoloadClasses['CaptchaSpecialPage'] |
| 191 | + = "$wgConfirmEditIP/ConfirmEdit_body.php"; |
| 192 | + |
| 193 | +/** |
| 194 | + * Set up $wgWhitelistRead |
| 195 | + */ |
| 196 | +function confirmEditSetup() { |
194 | 197 | global $wgGroupPermissions, $wgCaptchaTriggers; |
195 | 198 | if( !$wgGroupPermissions['*']['read'] && $wgCaptchaTriggers['badlogin'] ) { |
196 | 199 | // We need to ensure that the captcha interface is accessible |
— | — | @@ -203,596 +206,4 @@ |
204 | 207 | } |
205 | 208 | } |
206 | 209 | |
207 | | -/** |
208 | | - * Entry point for Special:Captcha |
209 | | - */ |
210 | | -function wfSpecialCaptcha( $par = null ) { |
211 | | - global $wgCaptcha; |
212 | | - switch( $par ) { |
213 | | - case "image": |
214 | | - return $wgCaptcha->showImage(); |
215 | | - case "help": |
216 | | - default: |
217 | | - return $wgCaptcha->showHelp(); |
218 | | - } |
219 | | -} |
220 | 210 | |
221 | | -class SimpleCaptcha { |
222 | | - function SimpleCaptcha() { |
223 | | - global $wgCaptchaStorageClass; |
224 | | - $this->storage = new $wgCaptchaStorageClass; |
225 | | - } |
226 | | - |
227 | | - /** |
228 | | - * Insert a captcha prompt into the edit form. |
229 | | - * This sample implementation generates a simple arithmetic operation; |
230 | | - * it would be easy to defeat by machine. |
231 | | - * |
232 | | - * Override this! |
233 | | - * |
234 | | - * @return string HTML |
235 | | - */ |
236 | | - function getForm() { |
237 | | - $a = mt_rand(0, 100); |
238 | | - $b = mt_rand(0, 10); |
239 | | - $op = mt_rand(0, 1) ? '+' : '-'; |
240 | | - |
241 | | - $test = "$a $op $b"; |
242 | | - $answer = ($op == '+') ? ($a + $b) : ($a - $b); |
243 | | - |
244 | | - $index = $this->storeCaptcha( array( 'answer' => $answer ) ); |
245 | | - |
246 | | - return "<p><label for=\"wpCaptchaWord\">$test</label> = " . |
247 | | - wfElement( 'input', array( |
248 | | - 'name' => 'wpCaptchaWord', |
249 | | - 'id' => 'wpCaptchaWord', |
250 | | - 'tabindex' => 1 ) ) . // tab in before the edit textarea |
251 | | - "</p>\n" . |
252 | | - wfElement( 'input', array( |
253 | | - 'type' => 'hidden', |
254 | | - 'name' => 'wpCaptchaId', |
255 | | - 'id' => 'wpCaptchaId', |
256 | | - 'value' => $index ) ); |
257 | | - } |
258 | | - |
259 | | - /** |
260 | | - * Insert the captcha prompt into an edit form. |
261 | | - * @param OutputPage $out |
262 | | - */ |
263 | | - function editCallback( &$out ) { |
264 | | - $out->addWikiText( $this->getMessage( $this->action ) ); |
265 | | - $out->addHTML( $this->getForm() ); |
266 | | - } |
267 | | - |
268 | | - /** |
269 | | - * Show a message asking the user to enter a captcha on edit |
270 | | - * The result will be treated as wiki text |
271 | | - * |
272 | | - * @param $action Action being performed |
273 | | - * @return string |
274 | | - */ |
275 | | - function getMessage( $action ) { |
276 | | - $name = 'captcha-' . $action; |
277 | | - $text = wfMsg( $name ); |
278 | | - # Obtain a more tailored message, if possible, otherwise, fall back to |
279 | | - # the default for edits |
280 | | - return wfEmptyMsg( $name, $text ) ? wfMsg( 'captcha-edit' ) : $text; |
281 | | - } |
282 | | - |
283 | | - /** |
284 | | - * Inject whazawhoo |
285 | | - * @fixme if multiple thingies insert a header, could break |
286 | | - * @param SimpleTemplate $template |
287 | | - * @return bool true to keep running callbacks |
288 | | - */ |
289 | | - function injectUserCreate( &$template ) { |
290 | | - global $wgCaptchaTriggers, $wgOut; |
291 | | - if( $wgCaptchaTriggers['createaccount'] ) { |
292 | | - $template->set( 'header', |
293 | | - "<div class='captcha'>" . |
294 | | - $wgOut->parse( $this->getMessage( 'createaccount' ) ) . |
295 | | - $this->getForm() . |
296 | | - "</div>\n" ); |
297 | | - } |
298 | | - return true; |
299 | | - } |
300 | | - |
301 | | - /** |
302 | | - * Inject a captcha into the user login form after a failed |
303 | | - * password attempt as a speedbump for mass attacks. |
304 | | - * @fixme if multiple thingies insert a header, could break |
305 | | - * @param SimpleTemplate $template |
306 | | - * @return bool true to keep running callbacks |
307 | | - */ |
308 | | - function injectUserLogin( &$template ) { |
309 | | - if( $this->isBadLoginTriggered() ) { |
310 | | - global $wgOut; |
311 | | - $template->set( 'header', |
312 | | - "<div class='captcha'>" . |
313 | | - $wgOut->parse( $this->getMessage( 'badlogin' ) ) . |
314 | | - $this->getForm() . |
315 | | - "</div>\n" ); |
316 | | - } |
317 | | - return true; |
318 | | - } |
319 | | - |
320 | | - /** |
321 | | - * When a bad login attempt is made, increment an expiring counter |
322 | | - * in the memcache cloud. Later checks for this may trigger a |
323 | | - * captcha display to prevent too many hits from the same place. |
324 | | - * @param User $user |
325 | | - * @param string $password |
326 | | - * @param int $retval authentication return value |
327 | | - * @return bool true to keep running callbacks |
328 | | - */ |
329 | | - function triggerUserLogin( $user, $password, $retval ) { |
330 | | - global $wgCaptchaTriggers, $wgCaptchaBadLoginExpiration, $wgMemc; |
331 | | - if( $retval == LoginForm::WRONG_PASS && $wgCaptchaTriggers['badlogin'] ) { |
332 | | - $key = $this->badLoginKey(); |
333 | | - $count = $wgMemc->get( $key ); |
334 | | - if( !$count ) { |
335 | | - $wgMemc->add( $key, 0, $wgCaptchaBadLoginExpiration ); |
336 | | - } |
337 | | - $count = $wgMemc->incr( $key ); |
338 | | - } |
339 | | - return true; |
340 | | - } |
341 | | - |
342 | | - /** |
343 | | - * Check if a bad login has already been registered for this |
344 | | - * IP address. If so, require a captcha. |
345 | | - * @return bool |
346 | | - * @access private |
347 | | - */ |
348 | | - function isBadLoginTriggered() { |
349 | | - global $wgMemc; |
350 | | - return intval( $wgMemc->get( $this->badLoginKey() ) ) > 0; |
351 | | - } |
352 | | - |
353 | | - /** |
354 | | - * Internal cache key for badlogin checks. |
355 | | - * @return string |
356 | | - * @access private |
357 | | - */ |
358 | | - function badLoginKey() { |
359 | | - return wfMemcKey( 'captcha', 'badlogin', 'ip', wfGetIP() ); |
360 | | - } |
361 | | - |
362 | | - /** |
363 | | - * Check if the submitted form matches the captcha session data provided |
364 | | - * by the plugin when the form was generated. |
365 | | - * |
366 | | - * Override this! |
367 | | - * |
368 | | - * @param WebRequest $request |
369 | | - * @param array $info |
370 | | - * @return bool |
371 | | - */ |
372 | | - function keyMatch( $request, $info ) { |
373 | | - return $request->getVal( 'wpCaptchaWord' ) == $info['answer']; |
374 | | - } |
375 | | - |
376 | | - // ---------------------------------- |
377 | | - |
378 | | - /** |
379 | | - * @param EditPage $editPage |
380 | | - * @param string $action (edit/create/addurl...) |
381 | | - * @return bool true if action triggers captcha on editPage's namespace |
382 | | - */ |
383 | | - function captchaTriggers( &$editPage, $action) { |
384 | | - global $wgCaptchaTriggers, $wgCaptchaTriggersOnNamespace; |
385 | | - //Special config for this NS? |
386 | | - if (isset( $wgCaptchaTriggersOnNamespace[$editPage->mTitle->getNamespace()][$action] ) ) |
387 | | - return $wgCaptchaTriggersOnNamespace[$editPage->mTitle->getNamespace()][$action]; |
388 | | - |
389 | | - return ( !empty( $wgCaptchaTriggers[$action] ) ); //Default |
390 | | - } |
391 | | - |
392 | | - |
393 | | - /** |
394 | | - * @param EditPage $editPage |
395 | | - * @param string $newtext |
396 | | - * @param string $section |
397 | | - * @return bool true if the captcha should run |
398 | | - */ |
399 | | - function shouldCheck( &$editPage, $newtext, $section ) { |
400 | | - $this->trigger = ''; |
401 | | - |
402 | | - global $wgUser; |
403 | | - if( $wgUser->isAllowed( 'skipcaptcha' ) ) { |
404 | | - wfDebug( "ConfirmEdit: user group allows skipping captcha\n" ); |
405 | | - return false; |
406 | | - } |
407 | | - global $wgCaptchaWhitelistIP; |
408 | | - if( !empty( $wgCaptchaWhitelistIP ) ) { |
409 | | - $ip = wfGetIp(); |
410 | | - foreach ( $wgCaptchaWhitelistIP as $range ) { |
411 | | - if ( IP::isInRange( $ip, $range ) ) { |
412 | | - return false; |
413 | | - } |
414 | | - } |
415 | | - } |
416 | | - |
417 | | - |
418 | | - global $wgEmailAuthentication, $ceAllowConfirmedEmail; |
419 | | - if( $wgEmailAuthentication && $ceAllowConfirmedEmail && |
420 | | - $wgUser->isEmailConfirmed() ) { |
421 | | - wfDebug( "ConfirmEdit: user has confirmed mail, skipping captcha\n" ); |
422 | | - return false; |
423 | | - } |
424 | | - |
425 | | - if( $this->captchaTriggers( $editPage, 'edit' ) ) { |
426 | | - // Check on all edits |
427 | | - global $wgUser, $wgTitle; |
428 | | - $this->trigger = sprintf( "edit trigger by '%s' at [[%s]]", |
429 | | - $wgUser->getName(), |
430 | | - $wgTitle->getPrefixedText() ); |
431 | | - $this->action = 'edit'; |
432 | | - wfDebug( "ConfirmEdit: checking all edits...\n" ); |
433 | | - return true; |
434 | | - } |
435 | | - |
436 | | - if( $this->captchaTriggers( $editPage, 'create' ) && !$editPage->mTitle->exists() ) { |
437 | | - //Check if creating a page |
438 | | - global $wgUser, $wgTitle; |
439 | | - $this->trigger = sprintf( "Create trigger by '%s' at [[%s]]", |
440 | | - $wgUser->getName(), |
441 | | - $wgTitle->getPrefixedText() ); |
442 | | - $this->action = 'create'; |
443 | | - wfDebug( "ConfirmEdit: checking on page creation...\n" ); |
444 | | - return true; |
445 | | - } |
446 | | - |
447 | | - if( $this->captchaTriggers( $editPage, 'addurl' ) ) { |
448 | | - // Only check edits that add URLs |
449 | | - $oldtext = $this->loadText( $editPage, $section ); |
450 | | - |
451 | | - $oldLinks = $this->findLinks( $oldtext ); |
452 | | - $newLinks = $this->findLinks( $newtext ); |
453 | | - $unknownLinks = array_filter( $newLinks, array( &$this, 'filterLink' ) ); |
454 | | - |
455 | | - $addedLinks = array_diff( $unknownLinks, $oldLinks ); |
456 | | - $numLinks = count( $addedLinks ); |
457 | | - |
458 | | - if( $numLinks > 0 ) { |
459 | | - global $wgUser, $wgTitle; |
460 | | - $this->trigger = sprintf( "%dx url trigger by '%s' at [[%s]]: %s", |
461 | | - $numLinks, |
462 | | - $wgUser->getName(), |
463 | | - $wgTitle->getPrefixedText(), |
464 | | - implode( ", ", $addedLinks ) ); |
465 | | - $this->action = 'addurl'; |
466 | | - return true; |
467 | | - } |
468 | | - } |
469 | | - |
470 | | - global $wgCaptchaRegexes; |
471 | | - if( !empty( $wgCaptchaRegexes ) ) { |
472 | | - // Custom regex checks |
473 | | - $oldtext = $this->loadText( $editPage, $section ); |
474 | | - |
475 | | - foreach( $wgCaptchaRegexes as $regex ) { |
476 | | - $newMatches = array(); |
477 | | - if( preg_match_all( $regex, $newtext, $newMatches ) ) { |
478 | | - $oldMatches = array(); |
479 | | - preg_match_all( $regex, $oldtext, $oldMatches ); |
480 | | - |
481 | | - $addedMatches = array_diff( $newMatches[0], $oldMatches[0] ); |
482 | | - |
483 | | - $numHits = count( $addedMatches ); |
484 | | - if( $numHits > 0 ) { |
485 | | - global $wgUser, $wgTitle; |
486 | | - $this->trigger = sprintf( "%dx %s at [[%s]]: %s", |
487 | | - $numHits, |
488 | | - $regex, |
489 | | - $wgUser->getName(), |
490 | | - $wgTitle->getPrefixedText(), |
491 | | - implode( ", ", $addedMatches ) ); |
492 | | - $this->action = 'edit'; |
493 | | - return true; |
494 | | - } |
495 | | - } |
496 | | - } |
497 | | - } |
498 | | - |
499 | | - return false; |
500 | | - } |
501 | | - |
502 | | - /** |
503 | | - * Filter callback function for URL whitelisting |
504 | | - * @param string url to check |
505 | | - * @return bool true if unknown, false if whitelisted |
506 | | - * @access private |
507 | | - */ |
508 | | - function filterLink( $url ) { |
509 | | - global $wgCaptchaWhitelist; |
510 | | - $source = wfMsgForContent( 'captcha-addurl-whitelist' ); |
511 | | - |
512 | | - $whitelist = wfEmptyMsg( 'captcha-addurl-whitelist', $source ) |
513 | | - ? false |
514 | | - : $this->buildRegexes( explode( "\n", $source ) ); |
515 | | - |
516 | | - $cwl = $wgCaptchaWhitelist !== false ? preg_match( $wgCaptchaWhitelist, $url ) : false; |
517 | | - $wl = $whitelist !== false ? preg_match( $whitelist, $url ) : false; |
518 | | - |
519 | | - return !( $cwl || $wl ); |
520 | | - } |
521 | | - |
522 | | - /** |
523 | | - * Build regex from whitelist |
524 | | - * @param string lines from [[MediaWiki:Captcha-addurl-whitelist]] |
525 | | - * @return string Regex or bool false if whitelist is empty |
526 | | - * @access private |
527 | | - */ |
528 | | - function buildRegexes( $lines ) { |
529 | | - # Code duplicated from the SpamBlacklist extension (r19197) |
530 | | - |
531 | | - # Strip comments and whitespace, then remove blanks |
532 | | - $lines = array_filter( array_map( 'trim', preg_replace( '/#.*$/', '', $lines ) ) ); |
533 | | - |
534 | | - # No lines, don't make a regex which will match everything |
535 | | - if ( count( $lines ) == 0 ) { |
536 | | - wfDebug( "No lines\n" ); |
537 | | - return false; |
538 | | - } else { |
539 | | - # Make regex |
540 | | - # It's faster using the S modifier even though it will usually only be run once |
541 | | - //$regex = 'http://+[a-z0-9_\-.]*(' . implode( '|', $lines ) . ')'; |
542 | | - //return '/' . str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $regex) ) . '/Si'; |
543 | | - $regexes = ''; |
544 | | - $regexStart = '/http:\/\/+[a-z0-9_\-.]*('; |
545 | | - $regexEnd = ')/Si'; |
546 | | - $regexMax = 4096; |
547 | | - $build = false; |
548 | | - foreach( $lines as $line ) { |
549 | | - // FIXME: not very robust size check, but should work. :) |
550 | | - if( $build === false ) { |
551 | | - $build = $line; |
552 | | - } elseif( strlen( $build ) + strlen( $line ) > $regexMax ) { |
553 | | - $regexes .= $regexStart . |
554 | | - str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $build) ) . |
555 | | - $regexEnd; |
556 | | - $build = $line; |
557 | | - } else { |
558 | | - $build .= '|' . $line; |
559 | | - } |
560 | | - } |
561 | | - if( $build !== false ) { |
562 | | - $regexes .= $regexStart . |
563 | | - str_replace( '/', '\/', preg_replace('|\\\*/|', '/', $build) ) . |
564 | | - $regexEnd; |
565 | | - } |
566 | | - return $regexes; |
567 | | - } |
568 | | - } |
569 | | - |
570 | | - /** |
571 | | - * The main callback run on edit attempts. |
572 | | - * @param EditPage $editPage |
573 | | - * @param string $newtext |
574 | | - * @param string $section |
575 | | - * @param bool true to continue saving, false to abort and show a captcha form |
576 | | - */ |
577 | | - function confirmEdit( &$editPage, $newtext, $section ) { |
578 | | - if( $this->shouldCheck( $editPage, $newtext, $section ) ) { |
579 | | - if( $this->passCaptcha() ) { |
580 | | - return true; |
581 | | - } else { |
582 | | - $editPage->showEditForm( array( &$this, 'editCallback' ) ); |
583 | | - return false; |
584 | | - } |
585 | | - } else { |
586 | | - wfDebug( "ConfirmEdit: no need to show captcha.\n" ); |
587 | | - return true; |
588 | | - } |
589 | | - } |
590 | | - |
591 | | - /** |
592 | | - * Hook for user creation form submissions. |
593 | | - * @param User $u |
594 | | - * @param string $message |
595 | | - * @return bool true to continue, false to abort user creation |
596 | | - */ |
597 | | - function confirmUserCreate( $u, &$message ) { |
598 | | - global $wgCaptchaTriggers; |
599 | | - if( $wgCaptchaTriggers['createaccount'] ) { |
600 | | - $this->trigger = "new account '" . $u->getName() . "'"; |
601 | | - if( !$this->passCaptcha() ) { |
602 | | - $message = wfMsg( 'captcha-createaccount-fail' ); |
603 | | - return false; |
604 | | - } |
605 | | - } |
606 | | - return true; |
607 | | - } |
608 | | - |
609 | | - /** |
610 | | - * Hook for user login form submissions. |
611 | | - * @param User $u |
612 | | - * @param string $message |
613 | | - * @return bool true to continue, false to abort user creation |
614 | | - */ |
615 | | - function confirmUserLogin( $u, $pass, &$retval ) { |
616 | | - if( $this->isBadLoginTriggered() ) { |
617 | | - $this->trigger = "post-badlogin login '" . $u->getName() . "'"; |
618 | | - if( !$this->passCaptcha() ) { |
619 | | - $message = wfMsg( 'captcha-badlogin-fail' ); |
620 | | - // Emulate a bad-password return to confuse the shit out of attackers |
621 | | - $retval = LoginForm::WRONG_PASS; |
622 | | - return false; |
623 | | - } |
624 | | - } |
625 | | - return true; |
626 | | - } |
627 | | - |
628 | | - /** |
629 | | - * Given a required captcha run, test form input for correct |
630 | | - * input on the open session. |
631 | | - * @return bool if passed, false if failed or new session |
632 | | - */ |
633 | | - function passCaptcha() { |
634 | | - $info = $this->retrieveCaptcha(); |
635 | | - if( $info ) { |
636 | | - global $wgRequest; |
637 | | - if( $this->keyMatch( $wgRequest, $info ) ) { |
638 | | - $this->log( "passed" ); |
639 | | - $this->clearCaptcha( $info ); |
640 | | - return true; |
641 | | - } else { |
642 | | - $this->clearCaptcha( $info ); |
643 | | - $this->log( "bad form input" ); |
644 | | - return false; |
645 | | - } |
646 | | - } else { |
647 | | - $this->log( "new captcha session" ); |
648 | | - return false; |
649 | | - } |
650 | | - } |
651 | | - |
652 | | - /** |
653 | | - * Log the status and any triggering info for debugging or statistics |
654 | | - * @param string $message |
655 | | - */ |
656 | | - function log( $message ) { |
657 | | - wfDebugLog( 'captcha', 'ConfirmEdit: ' . $message . '; ' . $this->trigger ); |
658 | | - } |
659 | | - |
660 | | - /** |
661 | | - * Generate a captcha session ID and save the info in PHP's session storage. |
662 | | - * (Requires the user to have cookies enabled to get through the captcha.) |
663 | | - * |
664 | | - * A random ID is used so legit users can make edits in multiple tabs or |
665 | | - * windows without being unnecessarily hobbled by a serial order requirement. |
666 | | - * Pass the returned id value into the edit form as wpCaptchaId. |
667 | | - * |
668 | | - * @param array $info data to store |
669 | | - * @return string captcha ID key |
670 | | - */ |
671 | | - function storeCaptcha( $info ) { |
672 | | - if( !isset( $info['index'] ) ) { |
673 | | - // Assign random index if we're not udpating |
674 | | - $info['index'] = strval( mt_rand() ); |
675 | | - } |
676 | | - $this->storage->store( $info['index'], $info ); |
677 | | - return $info['index']; |
678 | | - } |
679 | | - |
680 | | - /** |
681 | | - * Fetch this session's captcha info. |
682 | | - * @return mixed array of info, or false if missing |
683 | | - */ |
684 | | - function retrieveCaptcha() { |
685 | | - global $wgRequest; |
686 | | - $index = $wgRequest->getVal( 'wpCaptchaId' ); |
687 | | - return $this->storage->retrieve( $index ); |
688 | | - } |
689 | | - |
690 | | - /** |
691 | | - * Clear out existing captcha info from the session, to ensure |
692 | | - * it can't be reused. |
693 | | - */ |
694 | | - function clearCaptcha( $info ) { |
695 | | - $this->storage->clear( $info['index'] ); |
696 | | - } |
697 | | - |
698 | | - /** |
699 | | - * Retrieve the current version of the page or section being edited... |
700 | | - * @param EditPage $editPage |
701 | | - * @param string $section |
702 | | - * @return string |
703 | | - * @access private |
704 | | - */ |
705 | | - function loadText( $editPage, $section ) { |
706 | | - $rev = Revision::newFromTitle( $editPage->mTitle ); |
707 | | - if( is_null( $rev ) ) { |
708 | | - return ""; |
709 | | - } else { |
710 | | - $text = $rev->getText(); |
711 | | - if( $section != '' ) { |
712 | | - return Article::getSection( $text, $section ); |
713 | | - } else { |
714 | | - return $text; |
715 | | - } |
716 | | - } |
717 | | - } |
718 | | - |
719 | | - /** |
720 | | - * Extract a list of all recognized HTTP links in the text. |
721 | | - * @param string $text |
722 | | - * @return array of strings |
723 | | - */ |
724 | | - function findLinks( $text ) { |
725 | | - global $wgParser, $wgTitle, $wgUser; |
726 | | - |
727 | | - $options = new ParserOptions(); |
728 | | - $text = $wgParser->preSaveTransform( $text, $wgTitle, $wgUser, $options ); |
729 | | - $out = $wgParser->parse( $text, $wgTitle, $options ); |
730 | | - |
731 | | - return array_keys( $out->getExternalLinks() ); |
732 | | - } |
733 | | - |
734 | | - /** |
735 | | - * Show a page explaining what this wacky thing is. |
736 | | - */ |
737 | | - function showHelp() { |
738 | | - global $wgOut, $ceAllowConfirmedEmail; |
739 | | - $wgOut->setPageTitle( wfMsg( 'captchahelp-title' ) ); |
740 | | - $wgOut->addWikiText( wfMsg( 'captchahelp-text' ) ); |
741 | | - if ( $this->storage->cookiesNeeded() ) { |
742 | | - $wgOut->addWikiText( wfMsg( 'captchahelp-cookies-needed' ) ); |
743 | | - } |
744 | | - } |
745 | | - |
746 | | -} |
747 | | - |
748 | | -class CaptchaSessionStore { |
749 | | - function store( $index, $info ) { |
750 | | - $_SESSION['captcha' . $info['index']] = $info; |
751 | | - } |
752 | | - |
753 | | - function retrieve( $index ) { |
754 | | - if( isset( $_SESSION['captcha' . $index] ) ) { |
755 | | - return $_SESSION['captcha' . $index]; |
756 | | - } else { |
757 | | - return false; |
758 | | - } |
759 | | - } |
760 | | - |
761 | | - function clear( $index ) { |
762 | | - unset( $_SESSION['captcha' . $index] ); |
763 | | - } |
764 | | - |
765 | | - function cookiesNeeded() { |
766 | | - return true; |
767 | | - } |
768 | | -} |
769 | | - |
770 | | -class CaptchaCacheStore { |
771 | | - function store( $index, $info ) { |
772 | | - global $wgMemc, $wgCaptchaSessionExpiration; |
773 | | - $wgMemc->set( wfMemcKey( 'captcha', $index ), $info, |
774 | | - $wgCaptchaSessionExpiration ); |
775 | | - } |
776 | | - |
777 | | - function retrieve( $index ) { |
778 | | - global $wgMemc; |
779 | | - $info = $wgMemc->get( wfMemcKey( 'captcha', $index ) ); |
780 | | - if( $info ) { |
781 | | - return $info; |
782 | | - } else { |
783 | | - return false; |
784 | | - } |
785 | | - } |
786 | | - |
787 | | - function clear( $index ) { |
788 | | - global $wgMemc; |
789 | | - $wgMemc->delete( wfMemcKey( 'captcha', $index ) ); |
790 | | - } |
791 | | - |
792 | | - function cookiesNeeded() { |
793 | | - return false; |
794 | | - } |
795 | | -} |
796 | | - |
797 | | -} # End invocation guard |
798 | | - |
799 | | - |
Index: trunk/extensions/ConfirmEdit/FancyCaptcha.php |
— | — | @@ -24,7 +24,9 @@ |
25 | 25 | * @addtogroup Extensions |
26 | 26 | */ |
27 | 27 | |
28 | | -if ( defined( 'MEDIAWIKI' ) ) { |
| 28 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 29 | + exit; |
| 30 | +} |
29 | 31 | |
30 | 32 | global $wgCaptchaDirectory; |
31 | 33 | $wgCaptchaDirectory = "$wgUploadDirectory/captcha"; // bad default :D |
— | — | @@ -35,226 +37,6 @@ |
36 | 38 | global $wgCaptchaSecret; |
37 | 39 | $wgCaptchaSecret = "CHANGE_THIS_SECRET!"; |
38 | 40 | |
39 | | -$wgExtensionFunctions[] = 'efFancyCaptcha'; |
| 41 | +$wgExtensionMessagesFiles['FancyCaptcha'] = dirname(__FILE__).'/FancyCaptcha.i18n.php'; |
| 42 | +$wgAutoloadClasses['FancyCaptcha'] = dirname( __FILE__ ) . '/FancyCaptcha.class.php'; |
40 | 43 | |
41 | | -function efFancyCaptcha() { |
42 | | - global $wgMessageCache; |
43 | | - require_once( dirname( __FILE__ ) . '/FancyCaptcha.i18n.php' ); |
44 | | - foreach( efFancyCaptchaMessages() as $lang => $messages ) |
45 | | - $wgMessageCache->addMessages( $messages, $lang ); |
46 | | -} |
47 | | - |
48 | | -class FancyCaptcha extends SimpleCaptcha { |
49 | | - /** |
50 | | - * Check if the submitted form matches the captcha session data provided |
51 | | - * by the plugin when the form was generated. |
52 | | - * |
53 | | - * @param WebRequest $request |
54 | | - * @param array $info |
55 | | - * @return bool |
56 | | - */ |
57 | | - function keyMatch( $request, $info ) { |
58 | | - global $wgCaptchaSecret; |
59 | | - |
60 | | - $answer = $request->getVal( 'wpCaptchaWord' ); |
61 | | - $digest = $wgCaptchaSecret . $info['salt'] . $answer . $wgCaptchaSecret . $info['salt']; |
62 | | - $answerHash = substr( md5( $digest ), 0, 16 ); |
63 | | - |
64 | | - if( $answerHash == $info['hash'] ) { |
65 | | - wfDebug( "FancyCaptcha: answer hash matches expected {$info['hash']}\n" ); |
66 | | - return true; |
67 | | - } else { |
68 | | - wfDebug( "FancyCaptcha: answer hashes to $answerHash, expected {$info['hash']}\n" ); |
69 | | - return false; |
70 | | - } |
71 | | - } |
72 | | - |
73 | | - /** |
74 | | - * Insert the captcha prompt into the edit form. |
75 | | - */ |
76 | | - function getForm() { |
77 | | - $info = $this->pickImage(); |
78 | | - if( !$info ) { |
79 | | - die( "out of captcha images; this shouldn't happen" ); |
80 | | - } |
81 | | - |
82 | | - // Generate a random key for use of this captcha image in this session. |
83 | | - // This is needed so multiple edits in separate tabs or windows can |
84 | | - // go through without extra pain. |
85 | | - $index = $this->storeCaptcha( $info ); |
86 | | - |
87 | | - wfDebug( "Captcha id $index using hash ${info['hash']}, salt ${info['salt']}.\n" ); |
88 | | - |
89 | | - $title = Title::makeTitle( NS_SPECIAL, 'Captcha/image' ); |
90 | | - |
91 | | - return "<p>" . |
92 | | - wfElement( 'img', array( |
93 | | - 'src' => $title->getLocalUrl( 'wpCaptchaId=' . urlencode( $index ) ), |
94 | | - 'width' => $info['width'], |
95 | | - 'height' => $info['height'], |
96 | | - 'alt' => '' ) ) . |
97 | | - "</p>\n" . |
98 | | - wfElement( 'input', array( |
99 | | - 'type' => 'hidden', |
100 | | - 'name' => 'wpCaptchaId', |
101 | | - 'id' => 'wpCaptchaId', |
102 | | - 'value' => $index ) ) . |
103 | | - "<p>" . |
104 | | - wfElement( 'input', array( |
105 | | - 'name' => 'wpCaptchaWord', |
106 | | - 'id' => 'wpCaptchaWord', |
107 | | - 'tabindex' => 1 ) ) . // tab in before the edit textarea |
108 | | - "</p>\n"; |
109 | | - } |
110 | | - |
111 | | - /** |
112 | | - * Select a previously generated captcha image from the queue. |
113 | | - * @fixme subject to race conditions if lots of files vanish |
114 | | - * @return mixed tuple of (salt key, text hash) or false if no image to find |
115 | | - */ |
116 | | - function pickImage() { |
117 | | - global $wgCaptchaDirectory, $wgCaptchaDirectoryLevels; |
118 | | - return $this->pickImageDir( |
119 | | - $wgCaptchaDirectory, |
120 | | - $wgCaptchaDirectoryLevels ); |
121 | | - } |
122 | | - |
123 | | - function pickImageDir( $directory, $levels ) { |
124 | | - if( $levels ) { |
125 | | - $dirs = array(); |
126 | | - |
127 | | - // Check which subdirs are actually present... |
128 | | - $dir = opendir( $directory ); |
129 | | - while( false !== ($entry = readdir( $dir ) ) ) { |
130 | | - if( ctype_xdigit( $entry ) && strlen( $entry ) == 1 ) { |
131 | | - $dirs[] = $entry; |
132 | | - } |
133 | | - } |
134 | | - closedir( $dir ); |
135 | | - |
136 | | - $place = mt_rand( 0, count( $dirs ) - 1 ); |
137 | | - // In case all dirs are not filled, |
138 | | - // cycle through next digits... |
139 | | - for( $j = 0; $j < count( $dirs ); $j++ ) { |
140 | | - $char = $dirs[($place + $j) % count( $dirs )]; |
141 | | - $return = $this->pickImageDir( "$directory/$char", $levels - 1 ); |
142 | | - if( $return ) { |
143 | | - return $return; |
144 | | - } |
145 | | - } |
146 | | - // Didn't find any images in this directory... empty? |
147 | | - return false; |
148 | | - } else { |
149 | | - return $this->pickImageFromDir( $directory ); |
150 | | - } |
151 | | - } |
152 | | - |
153 | | - function pickImageFromDir( $directory ) { |
154 | | - if( !is_dir( $directory ) ) { |
155 | | - return false; |
156 | | - } |
157 | | - $n = mt_rand( 0, $this->countFiles( $directory ) - 1 ); |
158 | | - $dir = opendir( $directory ); |
159 | | - |
160 | | - $count = 0; |
161 | | - |
162 | | - $entry = readdir( $dir ); |
163 | | - $pick = false; |
164 | | - while( false !== $entry ) { |
165 | | - $entry = readdir( $dir ); |
166 | | - if( preg_match( '/^image_([0-9a-f]+)_([0-9a-f]+)\\.png$/', $entry, $matches ) ) { |
167 | | - $size = getimagesize( "$directory/$entry" ); |
168 | | - $pick = array( |
169 | | - 'salt' => $matches[1], |
170 | | - 'hash' => $matches[2], |
171 | | - 'width' => $size[0], |
172 | | - 'height' => $size[1], |
173 | | - 'viewed' => false, |
174 | | - ); |
175 | | - if( $count++ == $n ) { |
176 | | - break; |
177 | | - } |
178 | | - } |
179 | | - } |
180 | | - closedir( $dir ); |
181 | | - return $pick; |
182 | | - } |
183 | | - |
184 | | - /** |
185 | | - * Count the number of files in a directory. |
186 | | - * @return int |
187 | | - */ |
188 | | - function countFiles( $dirname ) { |
189 | | - $dir = opendir( $dirname ); |
190 | | - $count = 0; |
191 | | - while( false !== ($entry = readdir( $dir ) ) ) { |
192 | | - if( $entry != '.' && $entry != '..' ) { |
193 | | - $count++; |
194 | | - } |
195 | | - } |
196 | | - closedir( $dir ); |
197 | | - return $count; |
198 | | - } |
199 | | - |
200 | | - function showImage() { |
201 | | - global $wgOut, $wgRequest; |
202 | | - |
203 | | - $wgOut->disable(); |
204 | | - |
205 | | - $info = $this->retrieveCaptcha(); |
206 | | - if( $info ) { |
207 | | - if( $info['viewed'] ) { |
208 | | - wfHttpError( 403, 'Access Forbidden', "Can't view captcha image a second time." ); |
209 | | - return false; |
210 | | - } |
211 | | - |
212 | | - $info['viewed'] = wfTimestamp(); |
213 | | - $this->storeCaptcha( $info ); |
214 | | - |
215 | | - $salt = $info['salt']; |
216 | | - $hash = $info['hash']; |
217 | | - $file = $this->imagePath( $salt, $hash ); |
218 | | - |
219 | | - if( file_exists( $file ) ) { |
220 | | - global $IP; |
221 | | - require_once "$IP/includes/StreamFile.php"; |
222 | | - wfStreamFile( $file ); |
223 | | - return true; |
224 | | - } |
225 | | - } |
226 | | - wfHttpError( 500, 'Internal Error', 'Requested bogus captcha image' ); |
227 | | - return false; |
228 | | - } |
229 | | - |
230 | | - function imagePath( $salt, $hash ) { |
231 | | - global $wgCaptchaDirectory, $wgCaptchaDirectoryLevels; |
232 | | - $file = $wgCaptchaDirectory; |
233 | | - $file .= DIRECTORY_SEPARATOR; |
234 | | - for( $i = 0; $i < $wgCaptchaDirectoryLevels; $i++ ) { |
235 | | - $file .= $hash{$i}; |
236 | | - $file .= DIRECTORY_SEPARATOR; |
237 | | - } |
238 | | - $file .= "image_{$salt}_{$hash}.png"; |
239 | | - return $file; |
240 | | - } |
241 | | - |
242 | | - /** |
243 | | - * Show a message asking the user to enter a captcha on edit |
244 | | - * The result will be treated as wiki text |
245 | | - * |
246 | | - * @param $action Action being performed |
247 | | - * @return string |
248 | | - */ |
249 | | - function getMessage( $action ) { |
250 | | - $name = 'fancycaptcha-' . $action; |
251 | | - $text = wfMsg( $name ); |
252 | | - # Obtain a more tailored message, if possible, otherwise, fall back to |
253 | | - # the default for edits |
254 | | - return wfEmptyMsg( $name, $text ) ? wfMsg( 'fancycaptcha-edit' ) : $text; |
255 | | - } |
256 | | - |
257 | | -} |
258 | | - |
259 | | -} # End invocation guard |
260 | | - |
261 | | - |
Index: trunk/extensions/ConfirmEdit/FancyCaptcha.class.php |
— | — | @@ -0,0 +1,212 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class FancyCaptcha extends SimpleCaptcha { |
| 5 | + /** |
| 6 | + * Check if the submitted form matches the captcha session data provided |
| 7 | + * by the plugin when the form was generated. |
| 8 | + * |
| 9 | + * @param WebRequest $request |
| 10 | + * @param array $info |
| 11 | + * @return bool |
| 12 | + */ |
| 13 | + function keyMatch( $request, $info ) { |
| 14 | + global $wgCaptchaSecret; |
| 15 | + |
| 16 | + $answer = $request->getVal( 'wpCaptchaWord' ); |
| 17 | + $digest = $wgCaptchaSecret . $info['salt'] . $answer . $wgCaptchaSecret . $info['salt']; |
| 18 | + $answerHash = substr( md5( $digest ), 0, 16 ); |
| 19 | + |
| 20 | + if( $answerHash == $info['hash'] ) { |
| 21 | + wfDebug( "FancyCaptcha: answer hash matches expected {$info['hash']}\n" ); |
| 22 | + return true; |
| 23 | + } else { |
| 24 | + wfDebug( "FancyCaptcha: answer hashes to $answerHash, expected {$info['hash']}\n" ); |
| 25 | + return false; |
| 26 | + } |
| 27 | + } |
| 28 | + |
| 29 | + /** |
| 30 | + * Insert the captcha prompt into the edit form. |
| 31 | + */ |
| 32 | + function getForm() { |
| 33 | + $info = $this->pickImage(); |
| 34 | + if( !$info ) { |
| 35 | + die( "out of captcha images; this shouldn't happen" ); |
| 36 | + } |
| 37 | + |
| 38 | + // Generate a random key for use of this captcha image in this session. |
| 39 | + // This is needed so multiple edits in separate tabs or windows can |
| 40 | + // go through without extra pain. |
| 41 | + $index = $this->storeCaptcha( $info ); |
| 42 | + |
| 43 | + wfDebug( "Captcha id $index using hash ${info['hash']}, salt ${info['salt']}.\n" ); |
| 44 | + |
| 45 | + $title = Title::makeTitle( NS_SPECIAL, 'Captcha/image' ); |
| 46 | + |
| 47 | + return "<p>" . |
| 48 | + wfElement( 'img', array( |
| 49 | + 'src' => $title->getLocalUrl( 'wpCaptchaId=' . urlencode( $index ) ), |
| 50 | + 'width' => $info['width'], |
| 51 | + 'height' => $info['height'], |
| 52 | + 'alt' => '' ) ) . |
| 53 | + "</p>\n" . |
| 54 | + wfElement( 'input', array( |
| 55 | + 'type' => 'hidden', |
| 56 | + 'name' => 'wpCaptchaId', |
| 57 | + 'id' => 'wpCaptchaId', |
| 58 | + 'value' => $index ) ) . |
| 59 | + "<p>" . |
| 60 | + wfElement( 'input', array( |
| 61 | + 'name' => 'wpCaptchaWord', |
| 62 | + 'id' => 'wpCaptchaWord', |
| 63 | + 'tabindex' => 1 ) ) . // tab in before the edit textarea |
| 64 | + "</p>\n"; |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * Select a previously generated captcha image from the queue. |
| 69 | + * @fixme subject to race conditions if lots of files vanish |
| 70 | + * @return mixed tuple of (salt key, text hash) or false if no image to find |
| 71 | + */ |
| 72 | + function pickImage() { |
| 73 | + global $wgCaptchaDirectory, $wgCaptchaDirectoryLevels; |
| 74 | + return $this->pickImageDir( |
| 75 | + $wgCaptchaDirectory, |
| 76 | + $wgCaptchaDirectoryLevels ); |
| 77 | + } |
| 78 | + |
| 79 | + function pickImageDir( $directory, $levels ) { |
| 80 | + if( $levels ) { |
| 81 | + $dirs = array(); |
| 82 | + |
| 83 | + // Check which subdirs are actually present... |
| 84 | + $dir = opendir( $directory ); |
| 85 | + while( false !== ($entry = readdir( $dir ) ) ) { |
| 86 | + if( ctype_xdigit( $entry ) && strlen( $entry ) == 1 ) { |
| 87 | + $dirs[] = $entry; |
| 88 | + } |
| 89 | + } |
| 90 | + closedir( $dir ); |
| 91 | + |
| 92 | + $place = mt_rand( 0, count( $dirs ) - 1 ); |
| 93 | + // In case all dirs are not filled, |
| 94 | + // cycle through next digits... |
| 95 | + for( $j = 0; $j < count( $dirs ); $j++ ) { |
| 96 | + $char = $dirs[($place + $j) % count( $dirs )]; |
| 97 | + $return = $this->pickImageDir( "$directory/$char", $levels - 1 ); |
| 98 | + if( $return ) { |
| 99 | + return $return; |
| 100 | + } |
| 101 | + } |
| 102 | + // Didn't find any images in this directory... empty? |
| 103 | + return false; |
| 104 | + } else { |
| 105 | + return $this->pickImageFromDir( $directory ); |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + function pickImageFromDir( $directory ) { |
| 110 | + if( !is_dir( $directory ) ) { |
| 111 | + return false; |
| 112 | + } |
| 113 | + $n = mt_rand( 0, $this->countFiles( $directory ) - 1 ); |
| 114 | + $dir = opendir( $directory ); |
| 115 | + |
| 116 | + $count = 0; |
| 117 | + |
| 118 | + $entry = readdir( $dir ); |
| 119 | + $pick = false; |
| 120 | + while( false !== $entry ) { |
| 121 | + $entry = readdir( $dir ); |
| 122 | + if( preg_match( '/^image_([0-9a-f]+)_([0-9a-f]+)\\.png$/', $entry, $matches ) ) { |
| 123 | + $size = getimagesize( "$directory/$entry" ); |
| 124 | + $pick = array( |
| 125 | + 'salt' => $matches[1], |
| 126 | + 'hash' => $matches[2], |
| 127 | + 'width' => $size[0], |
| 128 | + 'height' => $size[1], |
| 129 | + 'viewed' => false, |
| 130 | + ); |
| 131 | + if( $count++ == $n ) { |
| 132 | + break; |
| 133 | + } |
| 134 | + } |
| 135 | + } |
| 136 | + closedir( $dir ); |
| 137 | + return $pick; |
| 138 | + } |
| 139 | + |
| 140 | + /** |
| 141 | + * Count the number of files in a directory. |
| 142 | + * @return int |
| 143 | + */ |
| 144 | + function countFiles( $dirname ) { |
| 145 | + $dir = opendir( $dirname ); |
| 146 | + $count = 0; |
| 147 | + while( false !== ($entry = readdir( $dir ) ) ) { |
| 148 | + if( $entry != '.' && $entry != '..' ) { |
| 149 | + $count++; |
| 150 | + } |
| 151 | + } |
| 152 | + closedir( $dir ); |
| 153 | + return $count; |
| 154 | + } |
| 155 | + |
| 156 | + function showImage() { |
| 157 | + global $wgOut, $wgRequest; |
| 158 | + |
| 159 | + $wgOut->disable(); |
| 160 | + |
| 161 | + $info = $this->retrieveCaptcha(); |
| 162 | + if( $info ) { |
| 163 | + if( $info['viewed'] ) { |
| 164 | + wfHttpError( 403, 'Access Forbidden', "Can't view captcha image a second time." ); |
| 165 | + return false; |
| 166 | + } |
| 167 | + |
| 168 | + $info['viewed'] = wfTimestamp(); |
| 169 | + $this->storeCaptcha( $info ); |
| 170 | + |
| 171 | + $salt = $info['salt']; |
| 172 | + $hash = $info['hash']; |
| 173 | + $file = $this->imagePath( $salt, $hash ); |
| 174 | + |
| 175 | + if( file_exists( $file ) ) { |
| 176 | + global $IP; |
| 177 | + require_once "$IP/includes/StreamFile.php"; |
| 178 | + wfStreamFile( $file ); |
| 179 | + return true; |
| 180 | + } |
| 181 | + } |
| 182 | + wfHttpError( 500, 'Internal Error', 'Requested bogus captcha image' ); |
| 183 | + return false; |
| 184 | + } |
| 185 | + |
| 186 | + function imagePath( $salt, $hash ) { |
| 187 | + global $wgCaptchaDirectory, $wgCaptchaDirectoryLevels; |
| 188 | + $file = $wgCaptchaDirectory; |
| 189 | + $file .= DIRECTORY_SEPARATOR; |
| 190 | + for( $i = 0; $i < $wgCaptchaDirectoryLevels; $i++ ) { |
| 191 | + $file .= $hash{$i}; |
| 192 | + $file .= DIRECTORY_SEPARATOR; |
| 193 | + } |
| 194 | + $file .= "image_{$salt}_{$hash}.png"; |
| 195 | + return $file; |
| 196 | + } |
| 197 | + |
| 198 | + /** |
| 199 | + * Show a message asking the user to enter a captcha on edit |
| 200 | + * The result will be treated as wiki text |
| 201 | + * |
| 202 | + * @param $action Action being performed |
| 203 | + * @return string |
| 204 | + */ |
| 205 | + function getMessage( $action ) { |
| 206 | + $name = 'fancycaptcha-' . $action; |
| 207 | + $text = wfMsg( $name ); |
| 208 | + # Obtain a more tailored message, if possible, otherwise, fall back to |
| 209 | + # the default for edits |
| 210 | + return wfEmptyMsg( $name, $text ) ? wfMsg( 'fancycaptcha-edit' ) : $text; |
| 211 | + } |
| 212 | + |
| 213 | +} |
Property changes on: trunk/extensions/ConfirmEdit/FancyCaptcha.class.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 214 | + native |