mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/AbuseFilter.git
synced 2024-09-24 02:38:16 +00:00
Abuse Filter Parser updates
* Deprecate parseTokens in favour of a parse-as-you-go approach, faster and uses less memory. * Display variables in lower_case so they aren't SHOUTING_AT_PEOPLE. * Tell people if they try to use variables that don't exist, rather than silently returning NULL.
This commit is contained in:
parent
e1d2743d7a
commit
35e61feeb6
|
@ -60,42 +60,42 @@ class AbuseFilter {
|
|||
'count(needle,haystack)' => 'count'
|
||||
),
|
||||
'vars' => array(
|
||||
'ACCOUNTNAME' => 'accountname',
|
||||
'ACTION' => 'action',
|
||||
'ADDED_LINES' => 'addedlines',
|
||||
'EDIT_DELTA' => 'delta',
|
||||
'EDIT_DIFF' => 'diff',
|
||||
'NEW_SIZE' => 'newsize',
|
||||
'OLD_SIZE' => 'oldsize',
|
||||
'REMOVED_LINES' => 'removedlines',
|
||||
'SUMMARY' => 'summary',
|
||||
'ARTICLE_ARTICLEID' => 'article-id',
|
||||
'ARTICLE_NAMESPACE' => 'article-ns',
|
||||
'ARTICLE_TEXT' => 'article-text',
|
||||
'ARTICLE_PREFIXEDTEXT' => 'article-prefixedtext',
|
||||
'MOVED_FROM_ARTICLEID' => 'movedfrom-id',
|
||||
'MOVED_FROM_NAMESPACE' => 'movedfrom-ns',
|
||||
'MOVED_FROM_TEXT' => 'movedfrom-text',
|
||||
'MOVED_FROM_PREFIXEDTEXT' => 'movedfrom-prefixedtext',
|
||||
'MOVED_TO_ARTICLEID' => 'movedto-id',
|
||||
'MOVED_TO_NAMESPACE' => 'movedto-ns',
|
||||
'MOVED_TO_TEXT' => 'movedto-text',
|
||||
'MOVED_TO_PREFIXEDTEXT' => 'movedto-prefixedtext',
|
||||
'USER_EDITCOUNT' => 'user-editcount',
|
||||
'USER_AGE' => 'user-age',
|
||||
'USER_NAME' => 'user-name',
|
||||
'USER_GROUPS' => 'user-groups',
|
||||
'USER_EMAILCONFIRM' => 'user-emailconfirm',
|
||||
'OLD_WIKITEXT' => 'old-text',
|
||||
'NEW_WIKITEXT' => 'new-text',
|
||||
'ADDED_LINKS' => 'added-links',
|
||||
'REMOVED_LINKS' => 'removed-links',
|
||||
'ALL_LINKS' => 'all-links',
|
||||
'NEW_TEXT' => 'new-text-stripped',
|
||||
'NEW_HTML' => 'new-html',
|
||||
'ARTICLE_RESTRICTIONS_edit' => 'restrictions-edit',
|
||||
'ARTICLE_RESTRICTIONS_move' => 'restrictions-move',
|
||||
'ARTICLE_RECENT_CONTRIBUTORS' => 'recent-contributors',
|
||||
'accountname' => 'accountname',
|
||||
'action' => 'action',
|
||||
'added_lines' => 'addedlines',
|
||||
'edit_delta' => 'delta',
|
||||
'edit_diff' => 'diff',
|
||||
'new_size' => 'newsize',
|
||||
'old_size' => 'oldsize',
|
||||
'removed_lines' => 'removedlines',
|
||||
'summary' => 'summary',
|
||||
'article_articleid' => 'article-id',
|
||||
'article_namespace' => 'article-ns',
|
||||
'article_text' => 'article-text',
|
||||
'article_prefixedtext' => 'article-prefixedtext',
|
||||
'moved_from_articleid' => 'movedfrom-id',
|
||||
'moved_from_namespace' => 'movedfrom-ns',
|
||||
'moved_from_text' => 'movedfrom-text',
|
||||
'moved_from_prefixedtext' => 'movedfrom-prefixedtext',
|
||||
'moved_to_articleid' => 'movedto-id',
|
||||
'moved_to_namespace' => 'movedto-ns',
|
||||
'moved_to_text' => 'movedto-text',
|
||||
'moved_to_prefixedtext' => 'movedto-prefixedtext',
|
||||
'user_editcount' => 'user-editcount',
|
||||
'user_age' => 'user-age',
|
||||
'user_name' => 'user-name',
|
||||
'user_groups' => 'user-groups',
|
||||
'user_emailconfirm' => 'user-emailconfirm',
|
||||
'old_wikitext' => 'old-text',
|
||||
'new_wikitext' => 'new-text',
|
||||
'added_links' => 'added-links',
|
||||
'removed_links' => 'removed-links',
|
||||
'all_links' => 'all-links',
|
||||
'new_text' => 'new-text-stripped',
|
||||
'new_html' => 'new-html',
|
||||
'article_restrictions_edit' => 'restrictions-edit',
|
||||
'article_restrictions_move' => 'restrictions-move',
|
||||
'article_recent_contributors' => 'recent-contributors',
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -1116,6 +1116,8 @@ class AbuseFilter {
|
|||
|
||||
// Now, build the body of the table.
|
||||
foreach( $vars as $key => $value ) {
|
||||
$key = strtolower($key);
|
||||
|
||||
if ( !empty($variableMessageMappings[$key]) ) {
|
||||
$mapping = $variableMessageMappings[$key];
|
||||
$keyDisplay = wfMsgExt( "abusefilter-edit-builder-vars-$mapping", 'parseinline' ) .
|
||||
|
|
|
@ -297,6 +297,7 @@ Please ask a user with permission to add restricted actions to make the change f
|
|||
'abusefilter-exception-unrecognisedtoken' => 'Unrecognised token "$2" at character $1.',
|
||||
'abusefilter-exception-noparams' => 'No parameters given to function "$2" at character $1.',
|
||||
'abusefilter-exception-dividebyzero' => 'Illegal attempt to divide $2 by zero at character $1.',
|
||||
'abusefilter-exception-unrecognisedvar' => 'Unrecognised variable $2 at character $1',
|
||||
|
||||
// Actions
|
||||
'abusefilter-action-throttle' => 'Throttle',
|
||||
|
|
|
@ -362,17 +362,15 @@ class AbuseFilterParser {
|
|||
wfProfileOut( __METHOD__ );
|
||||
}
|
||||
|
||||
protected function move( $shift = +1 ) {
|
||||
$old = $this->mPos;
|
||||
$this->mPos += $shift;
|
||||
if( $this->mPos >= 0 && $this->mPos < count( $this->mTokens ) ) {
|
||||
$this->mCur = $this->mTokens[$this->mPos];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
$this->mPos = $old;
|
||||
return false;
|
||||
}
|
||||
protected function move( ) {
|
||||
wfProfileIn( __METHOD__ );
|
||||
list( $val, $type, $code, $offset ) =
|
||||
self::nextToken( $this->mCode, $this->mPos );
|
||||
|
||||
$token = new AFPToken( $type, $val, $this->mPos );
|
||||
$this->mPos = $offset;
|
||||
wfProfileOut( __METHOD__ );
|
||||
return $this->mCur = $token;
|
||||
}
|
||||
|
||||
public function parse( $code ) {
|
||||
|
@ -385,10 +383,15 @@ class AbuseFilterParser {
|
|||
|
||||
function intEval( $code ) {
|
||||
wfProfileIn( __METHOD__ );
|
||||
|
||||
// Setup, resetting
|
||||
$this->mCode = $code;
|
||||
$this->mTokens = self::parseTokens( $code );
|
||||
$this->mPos = 0;
|
||||
$this->mCur = $this->mTokens[0];
|
||||
$this->mLen = strlen( $code );
|
||||
|
||||
// Parse the first token
|
||||
$this->move();
|
||||
|
||||
$result = new AFPData();
|
||||
$this->doLevelEntry( $result );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
@ -641,8 +644,17 @@ class AbuseFilterParser {
|
|||
$var = strtolower($tok);
|
||||
if( isset( $this->mVars[$var] ) ) {
|
||||
$result = $this->mVars[$var];
|
||||
} else {
|
||||
} elseif (
|
||||
array_key_exists( strtolower($var),
|
||||
AbuseFilter::$builderValues['vars'] )
|
||||
) {
|
||||
// If the variable is valid but not set, return null
|
||||
$result = new AFPData();
|
||||
} else {
|
||||
// If the variable is invalid, throw an exception
|
||||
throw new AFPUserVisibleException( 'unrecognisedvar',
|
||||
$this->mCur->pos,
|
||||
array( $var ) );
|
||||
}
|
||||
break;
|
||||
case AFPToken::TString:
|
||||
|
@ -662,7 +674,9 @@ class AbuseFilterParser {
|
|||
elseif( $tok == "null" )
|
||||
$result = new AFPData();
|
||||
else
|
||||
throw new AFPUserVisibleException( 'unrecognisedkeyword', $this->mCur->pos, array($tok) );
|
||||
throw new AFPUserVisibleException( 'unrecognisedkeyword',
|
||||
$this->mCur->pos,
|
||||
array($tok) );
|
||||
break;
|
||||
case AFPToken::TBrace:
|
||||
if( $this->mCur->value == ')' )
|
||||
|
@ -681,38 +695,17 @@ class AbuseFilterParser {
|
|||
|
||||
/* End of levels */
|
||||
|
||||
public static function parseTokens( $code ) {
|
||||
$r = array();
|
||||
$len = strlen( $code );
|
||||
$hash = md5(trim($code));
|
||||
|
||||
if (isset(self::$parserCache[$hash])) {
|
||||
return self::$parserCache[$hash];
|
||||
}
|
||||
|
||||
$offset = 0; // Where to next search
|
||||
while( $tok = self::nextToken( $code, $offset ) ) {
|
||||
$pos = $offset; // Start of the next token
|
||||
list( $val, $type, $code, $offset ) = $tok;
|
||||
$r[] = new AFPToken( $type, $val, $pos );
|
||||
if( $type == AFPToken::TNone )
|
||||
break;
|
||||
}
|
||||
|
||||
return self::$parserCache[$hash] = $r;
|
||||
}
|
||||
|
||||
static function nextToken( $code, $offset ) {
|
||||
$tok = '';
|
||||
|
||||
static $lastInput = array();
|
||||
|
||||
// if ( $lastInput == array( $code, $offset ) ) {
|
||||
// throw new AFPException( "Entered infinite loop. Offset $offset of $code" );
|
||||
// }
|
||||
if ( $lastInput == array( $code, $offset ) ) {
|
||||
throw new AFPException( "Entered infinite loop. Offset $offset of $code" );
|
||||
}
|
||||
|
||||
$lastInput = array( $code, $offset );
|
||||
|
||||
|
||||
while( !empty( $code[$offset] ) && ctype_space( $code[$offset] ) )
|
||||
$offset++;
|
||||
|
||||
|
|
Loading…
Reference in a new issue