Index: trunk/extensions/AbuseFilter/SpecialAbuseLog.php |
— | — | @@ -126,7 +126,7 @@ |
127 | 127 | $output .= Xml::element( 'h3', null, wfMsg( 'abusefilter-log-details-vars' ) ); |
128 | 128 | |
129 | 129 | // Build a table. |
130 | | - $vars = unserialize( $row->afl_var_dump ); |
| 130 | + $vars = AbuseFilter::loadVarDump( $row->afl_var_dump ); |
131 | 131 | |
132 | 132 | $output .= AbuseFilter::buildVarDumpTable( $vars ); |
133 | 133 | |
Index: trunk/extensions/AbuseFilter/Views/AbuseFilterViewExamine.php |
— | — | @@ -125,7 +125,7 @@ |
126 | 126 | return; |
127 | 127 | } |
128 | 128 | |
129 | | - $vars = unserialize( $row->afl_var_dump ); |
| 129 | + $vars = AbuseFilter::loadVarDump( $row->afl_var_dump ); |
130 | 130 | |
131 | 131 | $this->showExaminer( $vars ); |
132 | 132 | } |
Index: trunk/extensions/AbuseFilter/Views/AbuseFilterViewRevert.php |
— | — | @@ -140,7 +140,7 @@ |
141 | 141 | 'actions' => $currentReversibleActions, |
142 | 142 | 'user' => $row->afl_user_text, |
143 | 143 | 'userid' => $row->afl_user, |
144 | | - 'vars' => unserialize( $row->afl_var_dump ), |
| 144 | + 'vars' => AbuseFilter::loadVarDump( $row->afl_var_dump ), |
145 | 145 | 'title' => Title::makeTitle( $row->afl_namespace, $row->afl_title ), |
146 | 146 | 'action' => $row->afl_action, |
147 | 147 | 'timestamp' => $row->afl_timestamp |
Index: trunk/extensions/AbuseFilter/AbuseFilter.class.php |
— | — | @@ -435,12 +435,15 @@ |
436 | 436 | |
437 | 437 | list( $actions_taken, $error_msg ) = self::executeFilterActions( |
438 | 438 | array_keys( array_filter( $filter_matched ) ), $title, $vars ); |
| 439 | + |
| 440 | + $var_dump = self::storeVarDump( $vars ); |
| 441 | + $var_dump = "stored-text:$var_dump"; // To distinguish from stuff stored directly |
439 | 442 | |
440 | 443 | // Create a template |
441 | 444 | $log_template = array( |
442 | 445 | 'afl_user' => $wgUser->getId(), |
443 | 446 | 'afl_user_text' => $wgUser->getName(), |
444 | | - 'afl_var_dump' => serialize( $vars ), |
| 447 | + 'afl_var_dump' => $var_dump, |
445 | 448 | 'afl_timestamp' => $dbr->timestamp(wfTimestampNow()), |
446 | 449 | 'afl_namespace' => $title->getNamespace(), |
447 | 450 | 'afl_title' => $title->getDBKey(), |
— | — | @@ -493,6 +496,93 @@ |
494 | 497 | self::checkEmergencyDisable( $logged_filters, $total ); |
495 | 498 | } |
496 | 499 | |
| 500 | + /** Store a var dump to External Storage or the text table |
| 501 | + * Some of this code is stolen from Revision::insertOn and friends */ |
| 502 | + public static function storeVarDump( $vars ) { |
| 503 | + wfProfileIn( __METHOD__ ); |
| 504 | + |
| 505 | + if ( is_array( $vars ) || is_object( $vars ) ) |
| 506 | + $text = serialize( $vars ); |
| 507 | + else $text = $vars; |
| 508 | + |
| 509 | + $flags = array(); |
| 510 | + |
| 511 | + if (function_exists( 'gzdeflate' )) { |
| 512 | + $text = gzdeflate( $text ); |
| 513 | + $flags[] = 'gzip'; |
| 514 | + } |
| 515 | + |
| 516 | + // Store to ES if applicable |
| 517 | + global $wgDefaultExternalStore; |
| 518 | + if ($wgDefaultExternalStore) { |
| 519 | + $text = ExternalStore::insertToDefault( $text ); |
| 520 | + $flags[] = 'external'; |
| 521 | + |
| 522 | + if (!$text) |
| 523 | + // Not mission-critical, just return nothing |
| 524 | + return null; |
| 525 | + } |
| 526 | + |
| 527 | + // Store to text table |
| 528 | + $dbw = wfGetDB( DB_MASTER ); |
| 529 | + $old_id = $dbw->nextSequenceValue( 'text_old_id_val' ); |
| 530 | + $dbw->insert( 'text', |
| 531 | + array( |
| 532 | + 'old_id' => $old_id, |
| 533 | + 'old_text' => $text, |
| 534 | + 'old_flags' => implode( ',', $flags ), |
| 535 | + ), __METHOD__ |
| 536 | + ); |
| 537 | + $text_id = $dbw->insertId(); |
| 538 | + wfProfileOut( __METHOD__ ); |
| 539 | + |
| 540 | + return $text_id; |
| 541 | + } |
| 542 | + |
| 543 | + /** Retrieve a var dump from External Storage or the text table |
| 544 | + Some of this code is stolen from Revision::loadText et al */ |
| 545 | + public static function loadVarDump( $stored_dump ) { |
| 546 | + wfProfileIn( __METHOD__ ); |
| 547 | + |
| 548 | + // Back-compat |
| 549 | + if ( strpos( $stored_dump, 'stored-text:' ) === false ) { |
| 550 | + wfProfileOut( __METHOD__ ); |
| 551 | + return unserialize( $stored_dump ); |
| 552 | + } |
| 553 | + |
| 554 | + $text_id = substr( $stored_dump, strlen( 'stored-text:' ) ); |
| 555 | + |
| 556 | + $dbr = wfGetDB( DB_SLAVE ); |
| 557 | + |
| 558 | + $text_row = $dbr->selectRow( |
| 559 | + 'text', |
| 560 | + array( 'old_text', 'old_flags' ), |
| 561 | + array( 'old_id' => $text_id ), |
| 562 | + __METHOD__ |
| 563 | + ); |
| 564 | + |
| 565 | + if (!$text_row) { |
| 566 | + wfProfileOut( __METHOD__ ); |
| 567 | + return new AbuseFilterVariableHolder; |
| 568 | + } |
| 569 | + |
| 570 | + $flags = explode( ',', $text_row->old_flags ); |
| 571 | + $text = $text_row->old_text; |
| 572 | + |
| 573 | + if ( in_array( 'external', $flags ) ) { |
| 574 | + $text = ExternalStore::fetchFromURL( $text ); |
| 575 | + } |
| 576 | + |
| 577 | + if ( in_array( 'gzip', $flags ) ) { |
| 578 | + $text = gzinflate( $text ); |
| 579 | + } |
| 580 | + |
| 581 | + $obj = unserialize( $text ); |
| 582 | + |
| 583 | + wfProfileOut( __METHOD__ ); |
| 584 | + return $obj; |
| 585 | + } |
| 586 | + |
497 | 587 | public static function takeConsequenceAction( $action, $parameters, $title, |
498 | 588 | $vars, $rule_desc ) |
499 | 589 | { |
Index: trunk/extensions/AbuseFilter/abusefilter.tables.sql |
— | — | @@ -36,7 +36,7 @@ |
37 | 37 | afl_ip varchar(255) not null, |
38 | 38 | afl_action varbinary(255) not null, |
39 | 39 | afl_actions varbinary(255) not null, |
40 | | - afl_var_dump LONGBLOB NOT NULL, |
| 40 | + afl_var_dump BLOB NOT NULL, |
41 | 41 | afl_timestamp binary(14) NOT NULL, |
42 | 42 | afl_namespace tinyint NOT NULL, |
43 | 43 | afl_title varchar(255) binary NOT NULL, |