r39459 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r39458‎ | r39459 | r39460 >
Date:07:41, 16 August 2008
Author:werdna
Status:old
Tags:
Comment:
Remove PHP parser. It's totally inconsistent with the native parser now, and updating it wouldn't really be worth it (seeing as the native one would be used on Wikimedia)
Modified paths:
  • /trunk/extensions/AbuseFilter/AbuseFilter.parser.php (deleted) (history)
  • /trunk/extensions/AbuseFilter/AbuseFilter.php (modified) (history)

Diff [purge]

Index: trunk/extensions/AbuseFilter/AbuseFilter.parser.php
@@ -1,689 +0,0 @@
2 -<?php
3 -if ( ! defined( 'MEDIAWIKI' ) )
4 - die();
5 -/**
6 -Abuse filter parser.
7 -Copyright (C) Victor Vasiliev, 2008. Based on ideas by Andrew Garrett Distributed under GNU GPL v2 terms.
8 -
9 -Types of token:
10 -* T_NONE - special-purpose token
11 -* T_BRACE - ( or )
12 -* T_COMMA - ,
13 -* T_OP - operator like + or ^
14 -* T_NUMBER - number
15 -* T_STRING - string, in "" or ''
16 -* T_KEYWORD - keyword
17 -* T_ID - identifier
18 -
19 -Levels of parsing:
20 -* Set (S) - ==, +=, etc.
21 -* BoolOps (BO) - &, |, ^
22 -* CompOps (CO) - ==, !=, ===, !==, >, <, >=, <=
23 -* SumRel (SR) - +, -
24 -* MulRel (MR) - *, /, %
25 -* Pow (P) - **
26 -* BoolNeg (BN) - ! operation
27 -* SpecialOperators (SO) - in and like
28 -* Unarys (U) - plus and minus in cases like -5 or -(2 * +2)
29 -* Braces (B) - ( and )
30 -* Functions (F)
31 -* Atom (A) - return value
32 -*/
33 -
34 -class AFPToken {
35 - //Types of tken
36 - const TNone = 'T_NONE';
37 - const TID = 'T_ID';
38 - const TKeyword = 'T_KEYWORD';
39 - const TString = 'T_STRING';
40 - const TNumber = 'T_NUMBER';
41 - const TOp = 'T_OP';
42 - const TBrace = 'T_BRACE';
43 - const TComma = 'T_COMMA';
44 -
45 - var $type;
46 - var $value;
47 - var $pos;
48 -
49 - public function __construct( $type = self::TNone, $value = null, $pos = 0 ) {
50 - $this->type = $type;
51 - $this->value = $value;
52 - $this->pos = $pos;
53 - }
54 -}
55 -
56 -class AFPData {
57 - //Datatypes
58 - const DNumber = 'number'; //any integer or double
59 - const DString = 'string';
60 - const DNull = 'null';
61 - const DBool = 'bool';
62 -
63 - var $type;
64 - var $data;
65 -
66 - public function __construct( $type = self::DNull, $val = null ) {
67 - $this->type = $type;
68 - $this->data = $val;
69 - }
70 -
71 - public static function newFromPHPVar( $var ) {
72 - if( is_string( $var ) )
73 - return new AFPData( self::DString, $var );
74 - elseif( is_int( $var ) || is_float( $var ) )
75 - return new AFPData( self::DNumber, $var );
76 - elseif( is_bool( $var ) )
77 - return new AFPData( self::DBool, $var );
78 - elseif( is_null( $var ) )
79 - return new AFPData();
80 - else
81 - throw new AFPException( "Data type " . gettype( $var ) . " is not supported by AbuseFilter" );
82 - }
83 -
84 - public function dup() {
85 - return new AFPData( $this->type, $this->data );
86 - }
87 -
88 - public static function castTypes( $orig, $target ) {
89 - if( $orig->type == $target )
90 - return $orig->dup();
91 - if( $target == self::DNull ) {
92 - return new AFPData();
93 - }
94 - if( $target == self::DBool ) {
95 - return new AFPData( self::DBool, (bool)$orig->data );
96 - }
97 - if( $target == self::DNumber ) {
98 - return new AFPData( self::DNumber, doubleval( $orig->data ) );
99 - }
100 - if( $target == self::DString ) {
101 - return new AFPData( self::DString, strval( $orig->data ) );
102 - }
103 - }
104 -
105 - public static function boolInvert( $value ) {
106 - return new AFPData( self::DBool, !$value->toBool() );
107 - }
108 -
109 - public static function pow( $base, $exponent ) {
110 - return new AFPData( self::DNumber, pow( $base->toNumber(), $exponent->toNumber() ) );
111 - }
112 -
113 - public static function keywordIn( $a, $b ) {
114 - $a = $a->toString();
115 - $b = $b->toString();
116 -
117 - if ($a == '' || $b == '') {
118 - return new AFPData( self::DBool, false );
119 - }
120 -
121 - return new AFPData( self::DBool, in_string( $a, $b ) );
122 - }
123 -
124 - public static function keywordLike( $str, $regex ) {
125 - $str = $str->toString();
126 - $regex = $regex->toString() . 'u'; //Append unicode modifier
127 - wfSuppressWarnings();
128 - $result = preg_match( $regex, $str );
129 - wfRestoreWarnings();
130 - return new AFPData( self::DBool, (bool)$result );
131 - }
132 -
133 - public static function unaryMinus( $data ) {
134 - return new AFPData( self::DNumber, $data->toNumber() );
135 - }
136 -
137 - public static function boolOp( $a, $b, $op ) {
138 - $a = $a->toBool();
139 - $b = $b->toBool();
140 - if( $op == '|' )
141 - return new AFPData( self::DBool, $a || $b );
142 - if( $op == '&' )
143 - return new AFPData( self::DBool, $a && $b );
144 - if( $op == '^' )
145 - return new AFPData( self::DBool, $a xor $b );
146 - throw new AFPException( "Invalid boolean operation: {$op}" );
147 - }
148 -
149 - public static function compareOp( $a, $b, $op ) {
150 - if( $op == '==' )
151 - return new AFPData( self::DBool, $a->toString() === $b->toString() );
152 - if( $op == '!=' )
153 - return new AFPData( self::DBool, $a->toString() !== $b->toString() );
154 - if( $op == '===' )
155 - return new AFPData( self::DBool, $a->data === $b->data && $a->type == $b->type );
156 - if( $op == '!==' )
157 - return new AFPData( self::DBool, $a->data !== $b->data || $a->type != $b->type );
158 - $a = $a->toString();
159 - $b = $b->toString();
160 - if( $op == '>' )
161 - return new AFPData( self::DBool, $a > $b );
162 - if( $op == '<' )
163 - return new AFPData( self::DBool, $a < $b );
164 - if( $op == '>=' )
165 - return new AFPData( self::DBool, $a >= $b );
166 - if( $op == '<=' )
167 - return new AFPData( self::DBool, $a <= $b );
168 - throw new AFPException( "Invalid comprasion operation: {$op}" );
169 - }
170 -
171 - public static function mulRel( $a, $b, $op ) {
172 - $a = $a->toNumber();
173 - $b = $b->toNumber();
174 - if( $op == '*' )
175 - return new AFPData( self::DNumber, $a * $b );
176 - if( $op == '/' )
177 - return new AFPData( self::DNumber, $a / $b );
178 - if( $op == '%' )
179 - return new AFPData( self::DNumber, $a % $b );
180 - throw new AFPException( "Invalid multiplication-related operation: {$op}" );
181 - }
182 -
183 - public static function sum( $a, $b ) {
184 - if( $a->type == self::DString || $b->type == self::DString )
185 - return new AFPData( self::DString, $a->toString() . $b->toString() );
186 - else
187 - return new AFPData( self::DNumber, $a->toNumber() + $b->toNumber() );
188 - }
189 -
190 - public static function sub( $a, $b ) {
191 - return new AFPData( self::DNumber, $a->toNumber() - $b->toNumber() );
192 - }
193 -
194 - /** Convert shorteners */
195 - public function toBool() {
196 - return self::castTypes( $this, self::DBool )->data;
197 - }
198 -
199 - public function toString() {
200 - return self::castTypes( $this, self::DString )->data;
201 - }
202 -
203 - public function toNumber() {
204 - return self::castTypes( $this, self::DNumber )->data;
205 - }
206 -}
207 -
208 -class AFPException extends MWException {}
209 -
210 -class AbuseFilterParser {
211 - var $mParams, $mVars, $mCode, $mTokens, $mPos, $mCur;
212 -
213 - // length,lcase,ccnorm,rmdoubles,specialratio,rmspecials,norm,count
214 - static $mFunctions = array(
215 - 'lcase' => 'funcLc',
216 - 'length' => 'funcLen',
217 -// 'norm' => 'funcNorm',
218 -// 'ccnorm' => 'funcSimpleNorm',
219 -// 'specialratio' => 'funcSpecialRatio',
220 -// 'rmspecials' => 'funcRmSpecials',
221 -// 'count' => 'funcCount'
222 - );
223 - static $mOps = array(
224 - '!', '*', '**', '/', '+', '-', '%', '&', '|', '^',
225 - '<', '>', '>=', '<=', '==', '!=', '=', '===', '!==',
226 - );
227 - static $mKeywords = array(
228 - 'in', 'like', 'true', 'false', 'null',
229 - );
230 -
231 - static $parserCache = array();
232 -
233 - static $funcCache = array();
234 -
235 - public function __construct() {
236 - $this->resetState();
237 - }
238 -
239 - public function resetState() {
240 - $this->mParams = array();
241 - $this->mCode = '';
242 - $this->mTokens = array();
243 - $this->mVars = array();
244 - $this->mPos = 0;
245 - }
246 -
247 - public function checkSyntax( $filter ) {
248 - try {
249 - $this->parse($filter);
250 - } catch (AFPException $excep) {
251 - return $excep->getMessage();
252 - }
253 - return true;
254 - }
255 -
256 - public function setVar( $name, $var ) {
257 - $this->mVars[$name] = AFPData::newFromPHPVar( $var );
258 - }
259 -
260 - public function setVars( $vars ) {
261 - wfProfileIn( __METHOD__ );
262 - foreach( $vars as $name => $var ) {
263 - $this->setVar( $name, $var );
264 - }
265 - wfProfileOut( __METHOD__ );
266 - }
267 -
268 - protected function move( $shift = +1 ) {
269 - $old = $this->mPos;
270 - $this->mPos += $shift;
271 - if( $this->mPos >= 0 && $this->mPos < count( $this->mTokens ) ) {
272 - $this->mCur = $this->mTokens[$this->mPos];
273 - return true;
274 - }
275 - else {
276 - $this->mPos = $old;
277 - return false;
278 - }
279 - }
280 -
281 - public function parse( $code ) {
282 - wfProfileIn( __METHOD__ );
283 - $this->mCode = $code;
284 - $this->mTokens = self::parseTokens( $code );
285 - $this->mPos = 0;
286 - $this->mCur = $this->mTokens[0];
287 - $result = new AFPData();
288 - $this->doLevelEntry( $result );
289 - wfProfileOut( __METHOD__ );
290 - return $result->toBool();
291 - }
292 -
293 - public function evaluateExpression( $filter ) {
294 - wfProfileIn( __METHOD__ );
295 - $this->mCode = $code;
296 - $this->mTokens = self::parseTokens( $code );
297 - $this->mPos = 0;
298 - $this->mCur = $this->mTokens[0];
299 - $result = new AFPData();
300 - $this->doLevelEntry( $result );
301 - wfProfileOut( __METHOD__ );
302 - return $result->toString();
303 - }
304 -
305 - /* Levels */
306 -
307 - /** Handles unexpected characters after the expression */
308 - protected function doLevelEntry( &$result ) {
309 - $this->doLevelSet( $result );
310 - if( $this->mCur->type != AFPToken::TNone ) {
311 - throw new AFPException( "Unexpected {$this->mCur->type} at char {$this->mCur->pos}" );
312 - }
313 - }
314 -
315 - /** Handles "=" operator */
316 - protected function doLevelSet( &$result ) {
317 - wfProfileIn( __METHOD__ );
318 - if( $this->mCur->type == AFPToken::TID ) {
319 - $varname = $this->mCur->value;
320 - $this->move();
321 - if( $this->mCur->type == AFPToken::TOp && $this->mCur->value == '=' ) {
322 - $this->move();
323 - $this->doLevelSet( $result );
324 - $this->mVars[$varname] = $result->dup();
325 - return;
326 - }
327 - $this->move( -1 );
328 - }
329 - wfProfileOut( __METHOD__ );
330 - $this->doLevelBoolOps( $result );
331 - }
332 -
333 - protected function doLevelBoolOps( &$result ) {
334 - $this->doLevelCompares( $result );
335 - $ops = array( '&', '|', '^' );
336 - while( $this->mCur->type == AFPToken::TOp && in_array( $this->mCur->value, $ops ) ) {
337 - $op = $this->mCur->value;
338 - $this->move();
339 - $r2 = new AFPData();
340 - $this->doLevelCompares( $r2 );
341 - wfProfileIn( __METHOD__ );
342 - $result = AFPData::boolOp( $result, $r2, $op );
343 - wfProfileOut( __METHOD__ );
344 - }
345 - }
346 -
347 - protected function doLevelCompares( &$result ) {
348 - $this->doLevelMulRels( $result );
349 - $ops = array( '==', '===', '!=', '!==', '<', '>', '<=', '>=' );
350 - while( $this->mCur->type == AFPToken::TOp && in_array( $this->mCur->value, $ops ) ) {
351 - $op = $this->mCur->value;
352 - $this->move();
353 - $r2 = new AFPData();
354 - $this->doLevelMulRels( $r2 );
355 - wfProfileIn( __METHOD__ );
356 - $result = AFPData::compareOp( $result, $r2, $op );
357 - wfProfileOut( __METHOD__ );
358 - }
359 - }
360 -
361 - protected function doLevelMulRels( &$result ) {
362 - $this->doLevelSumRels( $result );
363 - wfProfileIn( __METHOD__ );
364 - $ops = array( '*', '/', '%' );
365 - while( $this->mCur->type == AFPToken::TOp && in_array( $this->mCur->value, $ops ) ) {
366 - $op = $this->mCur->value;
367 - $this->move();
368 - $r2 = new AFPData();
369 - $this->doLevelSumRels( $r2 );
370 - $result = AFPData::mulRel( $result, $r2, $op );
371 - }
372 - wfProfileOut( __METHOD__ );
373 - }
374 -
375 - protected function doLevelSumRels( &$result ) {
376 - $this->doLevelPow( $result );
377 - wfProfileIn( __METHOD__ );
378 - $ops = array( '+', '-' );
379 - while( $this->mCur->type == AFPToken::TOp && in_array( $this->mCur->value, $ops ) ) {
380 - $op = $this->mCur->value;
381 - $this->move();
382 - $r2 = new AFPData();
383 - $this->doLevelPow( $r2 );
384 - if( $op == '+' )
385 - $result = AFPData::sum( $result, $r2 );
386 - if( $op == '-' )
387 - $result = AFPData::sub( $result, $r2 );
388 - }
389 - wfProfileOut( __METHOD__ );
390 - }
391 -
392 - protected function doLevelPow( &$result ) {
393 - $this->doLevelBoolInvert( $result );
394 - wfProfileIn( __METHOD__ );
395 - while( $this->mCur->type == AFPToken::TOp && $this->mCur->value == '**' ) {
396 - $this->move();
397 - $expanent = new AFPData();
398 - $this->doLevelBoolInvert( $expanent );
399 - $result = AFPData::pow( $result, $expanent );
400 - }
401 - wfProfileOut( __METHOD__ );
402 - }
403 -
404 - protected function doLevelBoolInvert( &$result ) {
405 - if( $this->mCur->type == AFPToken::TOp && $this->mCur->value == '!' ) {
406 - $this->move();
407 - $this->doLevelSpecialWords( $result );
408 - wfProfileIn( __METHOD__ );
409 - $result = AFPData::boolInvert( $result );
410 - wfProfileOut( __METHOD__ );
411 - } else {
412 - $this->doLevelSpecialWords( $result );
413 - }
414 - }
415 -
416 - protected function doLevelSpecialWords( &$result ) {
417 - $this->doLevelUnarys( $result );
418 - $specwords = array( 'in', 'like' );
419 - if( $this->mCur->type == AFPToken::TKeyword && in_array( $this->mCur->value, $specwords ) ) {
420 - $func = 'keyword' . ucfirst( $this->mCur->value );
421 - $this->move();
422 - $r2 = new AFPData();
423 - $this->doLevelUnarys( $r2 );
424 - wfProfileIn( __METHOD__ );
425 - wfProfileIn( __METHOD__."-$func" );
426 - $result = AFPData::$func( $result, $r2 );
427 - wfProfileOut( __METHOD__."-$func" );
428 - wfProfileOut( __METHOD__ );
429 - }
430 - }
431 -
432 - protected function doLevelUnarys( &$result ) {
433 - $op = $this->mCur->value;
434 - if( $this->mCur->type == AFPToken::TOp && ( $op == "+" || $op == "-" ) ) {
435 - $this->move();
436 - $this->doLevelBraces( $result );
437 - wfProfileIn( __METHOD__ );
438 - if( $op == '-' ) {
439 - $result = AFPData::unaryMinus( $result );
440 - }
441 - wfProfileOut( __METHOD__ );
442 - } else {
443 - $this->doLevelBraces( $result );
444 - }
445 - }
446 -
447 - protected function doLevelBraces( &$result ) {
448 - if( $this->mCur->type == AFPToken::TBrace && $this->mCur->value == '(' ) {
449 - $this->move();
450 - $this->doLevelSet( $result );
451 - if( !($this->mCur->type == AFPToken::TBrace && $this->mCur->value == ')') )
452 - throw new AFPException( "Expected ) at char {$this->mCur->pos}" );
453 - $this->move();
454 - } else {
455 - $this->doLevelFunction( $result );
456 - }
457 - }
458 -
459 - protected function doLevelFunction( &$result ) {
460 - if( $this->mCur->type == AFPToken::TID && isset( self::$mFunctions[$this->mCur->value] ) ) {
461 - wfProfileIn( __METHOD__ );
462 - $func = self::$mFunctions[$this->mCur->value];
463 - $this->move();
464 - if( $this->mCur->type != AFPToken::TBrace || $this->mCur->value != '(' )
465 - throw new AFPEexception( "Expected ( at char {$this->mCur->value}" );
466 - wfProfileIn( __METHOD__."-loadargs" );
467 - $args = array();
468 - if( $this->mCur->type != AFPToken::TBrace || $this->mCur->value != ')' )
469 - do {
470 - $this->move();
471 - $r = new AFPData();
472 - try {
473 - $this->doLevelAtom( $r );
474 - } catch (AFPException $e) {
475 - $this->move( -1 );
476 - $this->doLevelSet( $r );
477 - }
478 - $args[] = $r;
479 - } while( $this->mCur->type == AFPToken::TComma );
480 - if( $this->mCur->type != AFPToken::TBrace || $this->mCur->value != ')' ) {
481 - throw new AFPException( "Expected ) at char {$this->mCur->pos}" );
482 - }
483 - wfProfileOut( __METHOD__."-loadargs" );
484 -
485 - wfProfileIn( __METHOD__."-$func" );
486 -
487 - $funcHash = md5($func.serialize($args));
488 -
489 - if (isset(self::$funcCache[$funcHash])) {
490 - $result = self::$funcCache[$funcHash];
491 - } else {
492 - $result = self::$funcCache[$funcHash] = $this->$func( $args );
493 - }
494 -
495 - if (count(self::$funcCache) > 1000) {
496 - self::$funcCache = array();
497 - }
498 -
499 - wfProfileOut( __METHOD__."-$func" );
500 -
501 - $this->move();
502 - wfProfileOut( __METHOD__ );
503 - } else {
504 - $this->doLevelAtom( $result );
505 - }
506 - }
507 -
508 - protected function doLevelAtom( &$result ) {
509 - wfProfileIn( __METHOD__ );
510 - $tok = $this->mCur->value;
511 - switch( $this->mCur->type ) {
512 - case AFPToken::TID:
513 - if( isset( $this->mVars[$tok] ) ) {
514 - $result = $this->mVars[$tok];
515 - } else {
516 - $result = new AFPData();
517 - }
518 - break;
519 - case AFPToken::TString:
520 - $result = new AFPData( AFPData::DString, $tok );
521 - break;
522 - case AFPToken::TNumber:
523 - $result = new AFPData( AFPData::DNumber, $tok );
524 - break;
525 - case AFPToken::TKeyword:
526 - if( $tok == "true" )
527 - $result = new AFPData( AFPData::DBool, true );
528 - elseif( $tok == "false" )
529 - $result = new AFPData( AFPData::DBool, false );
530 - elseif( $tok == "null" )
531 - $result = new AFPData();
532 - else
533 - throw new AFPException( "Unexpected {$this->mCur->type} at char {$this->mCur->pos}" );
534 - break;
535 - case AFPToken::TBrace:
536 - if( $this->mCur->value == ')' )
537 - return; // Handled at the entry level
538 - default:
539 - throw new AFPException( "Unexpected {$this->mCur->type} at char {$this->mCur->pos}" );
540 - }
541 - $this->move();
542 - wfProfileOut( __METHOD__ );
543 - }
544 -
545 - /* End of levels */
546 -
547 - public static function parseTokens( $code ) {
548 - $r = array();
549 - $len = strlen( $code );
550 - $hash = md5(trim($code));
551 -
552 - if (isset(self::$parserCache[$hash])) {
553 - return self::$parserCache[$hash];
554 - }
555 -
556 - while( $tok = self::nextToken( $code, $len ) ) {
557 - list( $val, $type, $code, $pos ) = $tok;
558 - $r[] = new AFPToken( $type, $val, $pos );
559 - if( $type == AFPToken::TNone )
560 - break;
561 - }
562 - return self::$parserCache[$hash] = $r;
563 - }
564 -
565 - protected static function nextToken( $code, $len ) {
566 - $tok = '';
567 - if( strlen( $code ) == 0 ) return array( '', AFPToken::TNone, $code, $len );
568 - while( ctype_space( $code[0] ) )
569 - $code = substr( $code, 1 );
570 - $pos = $len - strlen( $code );
571 - if( strlen( $code ) == 0 ) return array( '', AFPToken::TNone, $code, $pos );
572 - if( $code[0] == ',' )
573 - return array( ',', AFPToken::TComma, substr( $code, 1 ), $pos );
574 - if( $code[0] == '(' or $code[0] == ')' )
575 - return array( $code[0], AFPToken::TBrace, substr( $code, 1 ), $pos );
576 - if( $code[0] == '"' || $code[0] == "'" ) {
577 - $type = $code[0];
578 - $code = substr( $code, 1 );
579 - while( strlen( $code ) != 0 ) {
580 - if( $code[0] == $type ) {
581 - return array( $tok, AFPToken::TString, substr( $code, 1 ), $pos );
582 - }
583 - if( $code[0] == '\\' ) {
584 - if( $code[1] == '\\' )
585 - $tok .= '\\';
586 - elseif( $code[1] == $type )
587 - $tok .= $type;
588 - elseif( $code[1] == 'n' )
589 - $tok .= "\n";
590 - elseif( $code[1] == 'r' )
591 - $tok .= "\r";
592 - elseif( $code[1] == 't' )
593 - $tok .= "\t";
594 - else
595 - $tok .= $code[1];
596 - $code = substr( $code, 2 );
597 - } else {
598 - $tok .= $code[0];
599 - $code = substr( $code, 1 );
600 - }
601 - }
602 - throw new AFPException( "Unclosed string begining at char $pos" );
603 - }
604 - if( ctype_punct( $code[0] ) ) {
605 - $tok .= $code[0];
606 - $code = substr( $code, 1 );
607 - while( strlen( $code ) != 0 && ctype_punct( $code[0] ) ) {
608 - $tok .= $code[0];
609 - $code = substr( $code, 1 );
610 - }
611 - if( !in_array( $tok, self::$mOps ) )
612 - throw new AFPException( "Invalid operator: {$tok} (at char $pos)" );
613 - return array( $tok, AFPToken::TOp, $code, $pos );
614 - }
615 - if( ctype_digit( $code[0] ) ) {
616 - $tok .= $code[0];
617 - $code = substr( $code, 1 );
618 - while( strlen( $code ) != 0 && self::isDigitOrDot( $code[0] ) ) {
619 - $tok .= $code[0];
620 - $code = substr( $code, 1 );
621 - }
622 - return array( in_string( '.', $tok ) ? doubleval( $tok ) : intval( $tok ), AFPToken::TNumber, $code, $pos );
623 - }
624 - if( self::isValidIdSymbol( $code[0] ) ) {
625 - while( strlen( $code ) != 0 && self::isValidIdSymbol( $code[0] ) ) {
626 - $tok .= $code[0];
627 - $code = substr( $code, 1 );
628 - }
629 - $type = in_array( $tok, self::$mKeywords ) ? AFPToken::TKeyword : AFPToken::TID;
630 - return array( $tok, $type, $code, $pos );
631 - }
632 - throw new AFPException( "Unrecognized token \"{$code[0]}\" at char $pos" );
633 - }
634 -
635 - protected static function isDigitOrDot( $chr ) {
636 - return ctype_digit( $chr ) || $chr == '.';
637 - }
638 -
639 - protected static function isValidIdSymbol( $chr ) {
640 - return ctype_alnum( $chr ) || $chr == '_';
641 - }
642 -
643 - //Built-in functions
644 - protected function funcLc( $args ) {
645 - global $wgContLang;
646 - if( count( $args ) < 1 )
647 - throw new AFPExpection( "No params passed to lc()" );
648 - $s = $args[0]->toString();
649 - return new AFPData( AFPData::DString, $wgContLang->lc( $s ) );
650 - }
651 -
652 - protected function funcLen( $args ) {
653 - if( count( $args ) < 1 )
654 - throw new AFPExpection( "No params passed to len()" );
655 - $s = $args[0]->toString();
656 - return new AFPData( AFPData::DNumber, mb_strlen( $s, 'utf-8' ) );
657 - }
658 -
659 - protected function funcNorm( $args ) {
660 - if( count( $args ) < 1 )
661 - throw new AFPExpection( "No params passed to norm()" );
662 - $s = $args[0]->toString();
663 - return new AFPData( AFPData::DString, AbuseFilter::normalise( $s ) );
664 - }
665 -
666 - protected function funcSimpleNorm( $args ) {
667 - if( count( $args ) < 1 )
668 - throw new AFPExpection( "No params passed to simplenorm()" );
669 - $s = $args[0]->toString();
670 -
671 - $s = preg_replace( '/[\d\W]+/', '', $s );
672 - $s = strtolower( $value );
673 - return new AFPData( AFPData::DString, $s );
674 - }
675 -
676 - protected function funcSpecialRatio( $args ) {
677 - if( count( $args ) < 1 )
678 - throw new AFPExpection( "No params passed to simplenorm()" );
679 - $s = $args[0]->toString();
680 -
681 - if (!strlen($s)) {
682 - return new AFPData( AFPData::DNumber, 0 );
683 - }
684 -
685 - $specialsonly = preg_replace('/\w/', '', $s );
686 - $val = (strlen($specialsonly) / strlen($s));
687 -
688 - return new AFPData( AFPData::DNumber, $val );
689 - }
690 -}
Index: trunk/extensions/AbuseFilter/AbuseFilter.php
@@ -28,7 +28,6 @@
2929 $wgExtensionAliasesFiles['AbuseFilter'] = "$dir/AbuseFilter.alias.php";
3030
3131 $wgAutoloadClasses[ 'AbuseFilter' ] = "$dir/AbuseFilter.class.php";
32 -$wgAutoloadClasses[ 'AbuseFilterParser' ] = "$dir/AbuseFilter.parser.php";
3332 $wgAutoloadClasses[ 'AbuseFilterParserNative' ] = "$dir/AbuseFilter.nativeparser.php";
3433 $wgAutoloadClasses[ 'AbuseFilterHooks' ] = "$dir/AbuseFilter.hooks.php";
3534 $wgAutoloadClasses['SpecialAbuseLog'] = "$dir/SpecialAbuseLog.php";

Status & tagging log