Index: trunk/extensions/AbuseFilter/AbuseFilter.parser.php |
— | — | @@ -284,7 +284,7 @@ |
285 | 285 | } |
286 | 286 | |
287 | 287 | class AbuseFilterParser { |
288 | | - var $mParams, $mVars, $mCode, $mTokens, $mPos, $mCur, $mShortCircuit; |
| 288 | + var $mParams, $mVars, $mCode, $mTokens, $mPos, $mCur, $mShortCircuit, $mAllowShort; |
289 | 289 | |
290 | 290 | // length,lcase,ccnorm,rmdoubles,specialratio,rmspecials,norm,count |
291 | 291 | static $mFunctions = array( |
— | — | @@ -337,14 +337,20 @@ |
338 | 338 | $this->mTokens = array(); |
339 | 339 | $this->mVars = new AbuseFilterVariableHolder; |
340 | 340 | $this->mPos = 0; |
| 341 | + $this->mShortCircuit = false; |
| 342 | + $this->mAllowShort = true; |
341 | 343 | } |
342 | 344 | |
343 | 345 | public function checkSyntax( $filter ) { |
344 | 346 | try { |
| 347 | + $origAS = $this->mAllowShort; |
| 348 | + $this->mAllowShort = false; |
345 | 349 | $this->parse($filter); |
346 | 350 | } catch (AFPUserVisibleException $excep) { |
| 351 | + $this->mAllowShort = $origAS; |
347 | 352 | return array($excep->getMessage(), $excep->mPosition); |
348 | 353 | } |
| 354 | + $this->mAllowShort = $origAS; |
349 | 355 | return true; |
350 | 356 | } |
351 | 357 | |
— | — | @@ -374,6 +380,28 @@ |
375 | 381 | return $this->mCur = $token; |
376 | 382 | } |
377 | 383 | |
| 384 | + protected function skipOverBraces() { |
| 385 | + if( !($this->mCur->type == AFPToken::TBrace && $this->mCur->value == '(') || !$this->mShortCircuit ) { |
| 386 | + return; |
| 387 | + } |
| 388 | + |
| 389 | + $braces = 1; |
| 390 | + wfProfileIn( __METHOD__ ); |
| 391 | + while( $this->mCur->type != AFPToken::TNone && $braces > 0 ) { |
| 392 | + $this->move(); |
| 393 | + if( $this->mCur->type == AFPToken::TBrace ) { |
| 394 | + if( $this->mCur->value == '(' ) { |
| 395 | + $braces++; |
| 396 | + } elseif ($this->mCur->value == ')') { |
| 397 | + $braces--; |
| 398 | + } |
| 399 | + } |
| 400 | + } |
| 401 | + wfProfileOut( __METHOD__ ); |
| 402 | + if( !($this->mCur->type == AFPToken::TBrace && $this->mCur->value == ')') ) |
| 403 | + throw new AFPUserVisibleException( 'expectednotfound', $this->mCur->pos, array(')') ); |
| 404 | + } |
| 405 | + |
378 | 406 | public function parse( $code ) { |
379 | 407 | return $this->intEval( $code )->toBool(); |
380 | 408 | } |
— | — | @@ -387,6 +415,7 @@ |
388 | 416 | $this->mCode = $code; |
389 | 417 | $this->mPos = 0; |
390 | 418 | $this->mLen = strlen( $code ); |
| 419 | + $this->mShortCircuit = false; |
391 | 420 | |
392 | 421 | // Parse the first token |
393 | 422 | $this->move(); |
— | — | @@ -438,7 +467,7 @@ |
439 | 468 | |
440 | 469 | if ($isTrue) { |
441 | 470 | $scOrig = $this->mShortCircuit; |
442 | | - $this->mShortCircuit = true; |
| 471 | + $this->mShortCircuit = $this->mAllowShort; |
443 | 472 | } |
444 | 473 | $this->doLevelConditions( $r1 ); |
445 | 474 | if ($isTrue) { |
— | — | @@ -453,7 +482,7 @@ |
454 | 483 | |
455 | 484 | if (!$isTrue) { |
456 | 485 | $scOrig = $this->mShortCircuit; |
457 | | - $this->mShortCircuit = true; |
| 486 | + $this->mShortCircuit = $this->mAllowShort; |
458 | 487 | } |
459 | 488 | $this->doLevelConditions( $r2 ); |
460 | 489 | if (!$isTrue) { |
— | — | @@ -483,7 +512,7 @@ |
484 | 513 | |
485 | 514 | if ($isTrue) { |
486 | 515 | $scOrig = $this->mShortCircuit; |
487 | | - $this->mShortCircuit = true; |
| 516 | + $this->mShortCircuit = $this->mAllowShort; |
488 | 517 | } |
489 | 518 | $this->doLevelConditions( $r1 ); |
490 | 519 | if ($isTrue) { |
— | — | @@ -498,7 +527,7 @@ |
499 | 528 | |
500 | 529 | if (!$isTrue) { |
501 | 530 | $scOrig = $this->mShortCircuit; |
502 | | - $this->mShortCircuit = true; |
| 531 | + $this->mShortCircuit = $this->mAllowShort; |
503 | 532 | } |
504 | 533 | $this->doLevelConditions( $r2 ); |
505 | 534 | if (!$isTrue) { |
— | — | @@ -525,7 +554,7 @@ |
526 | 555 | if ( $op == '&' && !( $result->toBool() ) ) { |
527 | 556 | wfProfileIn( __METHOD__.'-shortcircuit' ); |
528 | 557 | $orig = $this->mShortCircuit; |
529 | | - $this->mShortCircuit = true; |
| 558 | + $this->mShortCircuit = $this->mAllowShort; |
530 | 559 | $this->doLevelCompares( $r2 ); |
531 | 560 | $this->mShortCircuit = $orig; |
532 | 561 | $result = new AFPData( AFPData::DBool, false ); |
— | — | @@ -536,7 +565,7 @@ |
537 | 566 | if ( $op == '|' && $result->toBool() ) { |
538 | 567 | wfProfileIn( __METHOD__.'-shortcircuit' ); |
539 | 568 | $orig = $this->mShortCircuit; |
540 | | - $this->mShortCircuit = true; |
| 569 | + $this->mShortCircuit = $this->mAllowShort; |
541 | 570 | $this->doLevelCompares( $r2 ); |
542 | 571 | $this->mShortCircuit = $orig; |
543 | 572 | $result = new AFPData( AFPData::DBool, true ); |
— | — | @@ -662,8 +691,12 @@ |
663 | 692 | |
664 | 693 | protected function doLevelBraces( &$result ) { |
665 | 694 | if( $this->mCur->type == AFPToken::TBrace && $this->mCur->value == '(' ) { |
666 | | - $this->move(); |
667 | | - $this->doLevelSet( $result ); |
| 695 | + if( $this->mShortCircuit ) { |
| 696 | + $this->skipOverBraces(); |
| 697 | + } else { |
| 698 | + $this->move(); |
| 699 | + $this->doLevelSet( $result ); |
| 700 | + } |
668 | 701 | if( !($this->mCur->type == AFPToken::TBrace && $this->mCur->value == ')') ) |
669 | 702 | throw new AFPUserVisibleException( 'expectednotfound', |
670 | 703 | $this->mCur->pos, |
— | — | @@ -683,6 +716,14 @@ |
684 | 717 | throw new AFPUserVisibleException( 'expectednotfound', |
685 | 718 | $this->mCur->pos, |
686 | 719 | array('(', $this->mCur->type, $this->mCur->value ) ); |
| 720 | + |
| 721 | + if ($this->mShortCircuit) { |
| 722 | + $this->skipOverBraces(); |
| 723 | + $this->move(); |
| 724 | + wfProfileOut( __METHOD__ ); |
| 725 | + return; // The result doesn't matter. |
| 726 | + } |
| 727 | + |
687 | 728 | wfProfileIn( __METHOD__."-loadargs" ); |
688 | 729 | $args = array(); |
689 | 730 | do { |
— | — | @@ -701,11 +742,6 @@ |
702 | 743 | |
703 | 744 | wfProfileOut( __METHOD__."-loadargs" ); |
704 | 745 | |
705 | | - if ($this->mShortCircuit) { |
706 | | - wfProfileOut( __METHOD__ ); |
707 | | - return; // The result doesn't matter. |
708 | | - } |
709 | | - |
710 | 746 | wfProfileIn( __METHOD__."-$func" ); |
711 | 747 | |
712 | 748 | $funcHash = md5($func.serialize($args)); |