mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/AbuseFilter.git
synced 2024-11-23 21:53:35 +00:00
Add support for regex string replacements.
Bug: T285468 Change-Id: I25f8ad1b58cc10f4c6f6ef5ebab99fe58ec71b1e
This commit is contained in:
parent
81b99aad53
commit
1d1215bafb
|
@ -343,6 +343,7 @@
|
|||
"abusefilter-edit-builder-funcs-substr": "Substring (substr)",
|
||||
"abusefilter-edit-builder-funcs-strpos": "Position of substring in string (strpos)",
|
||||
"abusefilter-edit-builder-funcs-str_replace": "Replace substring with string (str_replace)",
|
||||
"abusefilter-edit-builder-funcs-str_replace_regexp": "Regular expression search and replace (str_replace_regexp)",
|
||||
"abusefilter-edit-builder-funcs-rescape": "Escape string as literal in regex (rescape)",
|
||||
"abusefilter-edit-builder-funcs-set_var": "Set variable (set_var)",
|
||||
"abusefilter-edit-builder-funcs-sanitize": "Normalize HTML entities into unicode characters (sanitize)",
|
||||
|
|
|
@ -385,6 +385,7 @@
|
|||
"abusefilter-edit-builder-funcs-substr": "{{doc-important|Do not translate \"'''substr'''\".}} Abuse filter syntax option in a dropdown from the group {{msg-mw|abusefilter-edit-builder-group-funcs}}.",
|
||||
"abusefilter-edit-builder-funcs-strpos": "{{doc-important|Do not translate \"'''strpos'''\".}} Abuse filter syntax option in a dropdown from the group {{msg-mw|abusefilter-edit-builder-group-funcs}}.",
|
||||
"abusefilter-edit-builder-funcs-str_replace": "{{doc-important|Do not translate \"'''str_replace'''\".}} Abuse filter syntax option in a dropdown from the group {{msg-mw|abusefilter-edit-builder-group-funcs}}.",
|
||||
"abusefilter-edit-builder-funcs-str_replace_regexp": "{{doc-important|Do not translate \"'''str_replace_regexp'''\".}} Abuse filter syntax option in a dropdown from the group {{msg-mw|abusefilter-edit-builder-group-funcs}}.\n\n\"regexp\" stands for \"regular expression\".",
|
||||
"abusefilter-edit-builder-funcs-rescape": "{{doc-important|Do not translate \"'''rescape'''\".}}\nAbuse filter syntax option in a dropdown from the group {{msg-mw|abusefilter-edit-builder-group-funcs}}.\n\n\"regex\" stands for \"regular expression\".",
|
||||
"abusefilter-edit-builder-funcs-set_var": "{{doc-important|Do not translate \"'''set_var'''\".}}\nAbuse filter syntax option in a dropdown from the group {{msg-mw|abusefilter-edit-builder-group-funcs}}.",
|
||||
"abusefilter-edit-builder-funcs-sanitize": "{{doc-important|Do not translate \"'''sanitize'''\".}}\nAbuse filter syntax option in a dropdown from the group {{msg-mw|abusefilter-edit-builder-group-funcs}}.",
|
||||
|
|
|
@ -68,6 +68,7 @@ class KeywordsManager {
|
|||
'substr(subject, offset, length)' => 'substr',
|
||||
'strpos(haystack, needle)' => 'strpos',
|
||||
'str_replace(subject, search, replace)' => 'str_replace',
|
||||
'str_replace_regexp(subject, search, replace)' => 'str_replace_regexp',
|
||||
'rescape(string)' => 'rescape',
|
||||
'set_var(var,value)' => 'set_var',
|
||||
'sanitize(string)' => 'sanitize',
|
||||
|
|
|
@ -59,6 +59,7 @@ class FilterEvaluator {
|
|||
'strlen' => 'funcLen',
|
||||
'strpos' => 'funcStrPos',
|
||||
'str_replace' => 'funcStrReplace',
|
||||
'str_replace_regexp' => 'funcStrReplaceRegexp',
|
||||
'rescape' => 'funcStrRegexEscape',
|
||||
'set' => 'funcSetVar',
|
||||
'set_var' => 'funcSetVar',
|
||||
|
@ -96,6 +97,7 @@ class FilterEvaluator {
|
|||
'strlen' => [ 1, 1 ],
|
||||
'strpos' => [ 2, 3 ],
|
||||
'str_replace' => [ 3, 3 ],
|
||||
'str_replace_regexp' => [ 3, 3 ],
|
||||
'rescape' => [ 1, 1 ],
|
||||
'set' => [ 2, 2 ],
|
||||
'set_var' => [ 2, 2 ],
|
||||
|
@ -1289,6 +1291,35 @@ class FilterEvaluator {
|
|||
return new AFPData( AFPData::DSTRING, str_replace( $search, $replace, $subject ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
* @param int $position
|
||||
* @return AFPData
|
||||
*/
|
||||
protected function funcStrReplaceRegexp( $args, int $position ) {
|
||||
$subject = $args[0]->toString();
|
||||
$search = $args[1]->toString();
|
||||
$replace = $args[2]->toString();
|
||||
|
||||
$this->checkRegexMatchesEmpty( $args[1], $search, $position );
|
||||
// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
|
||||
$result = @preg_replace(
|
||||
$this->mungeRegexp( $search ),
|
||||
$replace,
|
||||
$subject
|
||||
);
|
||||
|
||||
if ( $result === null ) {
|
||||
throw new UserVisibleException(
|
||||
'regexfailure',
|
||||
$position,
|
||||
[ $search ]
|
||||
);
|
||||
}
|
||||
|
||||
return new AFPData( AFPData::DSTRING, $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
* @return AFPData
|
||||
|
|
3
tests/parserTests/str-replace-regexp.t
Normal file
3
tests/parserTests/str-replace-regexp.t
Normal file
|
@ -0,0 +1,3 @@
|
|||
str_replace_regexp( "foobarbaz", "bar", "" ) === 'foobaz' &
|
||||
str_replace_regexp( "foo1bar1baz", "\d", "" ) === 'foobarbaz' &
|
||||
str_replace_regexp( "foobarbaz", "(bar)", "$1baz" ) === 'foobarbazbaz'
|
|
@ -96,9 +96,11 @@ class ParserTest extends ParserTestCase {
|
|||
[ '1 === 1', true ],
|
||||
[ 'rescape( "abc* (def)" )', 'abc\* \(def\)' ],
|
||||
[ 'str_replace( "foobarbaz", "bar", "-" )', 'foo-baz' ],
|
||||
[ 'str_replace_regexp( "foo1bar1baz", "\d", "" )', 'foobarbaz' ],
|
||||
[ 'str_replace_regexp( "foobarbaz", "(bar)", "$1baz" )', 'foobarbazbaz' ],
|
||||
[ 'rmdoubles( "foobybboo" )', 'fobybo' ],
|
||||
[ 'lcase("FÁmí")', 'fámí' ],
|
||||
[ 'substr( "foobar", 0, 3 )', 'foo' ]
|
||||
[ 'substr( "foobar", 0, 3 )', 'foo' ],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -552,6 +554,7 @@ class ParserTest extends ParserTestCase {
|
|||
[ "rcount('(','a')", 'funcRCount' ],
|
||||
[ "get_matches('this (should fail', 'any haystack')", 'funcGetMatches' ],
|
||||
[ "'a' rlike '('", 'keywordRegex' ],
|
||||
[ "str_replace_regexp('any string', 'a bad (regex', 'any replacement')", 'funcStrReplaceRegexp' ],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -679,6 +682,7 @@ class ParserTest extends ParserTestCase {
|
|||
public function threeParamsFuncs() {
|
||||
return [
|
||||
[ 'str_replace' ],
|
||||
[ 'str_replace_regexp' ],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -702,6 +706,7 @@ class ParserTest extends ParserTestCase {
|
|||
[ "ip_in_range( 'a', 'b', 'c' )" ],
|
||||
[ "substr( 'a', 'b', 'c', 'd' )" ],
|
||||
[ "str_replace( 'a', 'b', 'c', 'd', 'e' )" ],
|
||||
[ "str_replace_regexp( 'a', 'b', 'c', 'd', 'e' )" ],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -761,7 +766,8 @@ class ParserTest extends ParserTestCase {
|
|||
[ 'bool()', 'noparams' ],
|
||||
[ 'ip_in_range(1)', 'notenoughargs' ],
|
||||
[ 'set_var("x")', 'notenoughargs' ],
|
||||
[ 'str_replace("x","y")', 'notenoughargs' ]
|
||||
[ 'str_replace("x","y")', 'notenoughargs' ],
|
||||
[ 'str_replace_regexp("x","y")', 'notenoughargs' ],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -1099,6 +1105,7 @@ class ParserTest extends ParserTestCase {
|
|||
return [
|
||||
[ "norm(,,,)" ],
|
||||
[ "str_replace(,'x','y')" ],
|
||||
[ "str_replace_regexp(,'x','y')" ],
|
||||
[ "contains_any(,)" ],
|
||||
[ "contains_any(,,)" ],
|
||||
[ "contains_any(1,2,,)" ],
|
||||
|
|
Loading…
Reference in a new issue