00001 <?php
00002
00044 class RecentChange {
00045 var $mAttribs = array(), $mExtra = array();
00046 var $mTitle = false, $mMovedToTitle = false;
00047 var $numberofWatchingusers = 0 ; # Dummy to prevent error message in SpecialRecentchangeslinked
00048
00049 # Factory methods
00050
00051 public static function newFromRow( $row ) {
00052 $rc = new RecentChange;
00053 $rc->loadFromRow( $row );
00054 return $rc;
00055 }
00056
00057 public static function newFromCurRow( $row ) {
00058 $rc = new RecentChange;
00059 $rc->loadFromCurRow( $row );
00060 $rc->notificationtimestamp = false;
00061 $rc->numberofWatchingusers = false;
00062 return $rc;
00063 }
00064
00071 public static function newFromId( $rcid ) {
00072 $dbr = wfGetDB( DB_SLAVE );
00073 $res = $dbr->select( 'recentchanges', '*', array( 'rc_id' => $rcid ), __METHOD__ );
00074 if( $res && $dbr->numRows( $res ) > 0 ) {
00075 $row = $dbr->fetchObject( $res );
00076 $dbr->freeResult( $res );
00077 return self::newFromRow( $row );
00078 } else {
00079 return null;
00080 }
00081 }
00082
00090 public static function newFromConds( $conds, $fname = false ) {
00091 if( $fname === false )
00092 $fname = __METHOD__;
00093 $dbr = wfGetDB( DB_SLAVE );
00094 $res = $dbr->select(
00095 'recentchanges',
00096 '*',
00097 $conds,
00098 $fname
00099 );
00100 if( $res instanceof ResultWrapper && $res->numRows() > 0 ) {
00101 $row = $res->fetchObject();
00102 $res->free();
00103 return self::newFromRow( $row );
00104 }
00105 return null;
00106 }
00107
00108 # Accessors
00109
00110 public function setAttribs( $attribs ) {
00111 $this->mAttribs = $attribs;
00112 }
00113
00114 public function setExtra( $extra ) {
00115 $this->mExtra = $extra;
00116 }
00117
00118 public function &getTitle() {
00119 if( $this->mTitle === false ) {
00120 $this->mTitle = Title::makeTitle( $this->mAttribs['rc_namespace'], $this->mAttribs['rc_title'] );
00121 # Make sure the correct page ID is process cached
00122 $this->mTitle->resetArticleID( $this->mAttribs['rc_cur_id'] );
00123 }
00124 return $this->mTitle;
00125 }
00126
00127 public function getMovedToTitle() {
00128 if( $this->mMovedToTitle === false ) {
00129 $this->mMovedToTitle = Title::makeTitle( $this->mAttribs['rc_moved_to_ns'],
00130 $this->mAttribs['rc_moved_to_title'] );
00131 }
00132 return $this->mMovedToTitle;
00133 }
00134
00135 # Writes the data in this object to the database
00136 public function save() {
00137 global $wgLocalInterwiki, $wgPutIPinRC, $wgRC2UDPAddress, $wgRC2UDPOmitBots;
00138 $fname = 'RecentChange::save';
00139
00140 $dbw = wfGetDB( DB_MASTER );
00141 if( !is_array($this->mExtra) ) {
00142 $this->mExtra = array();
00143 }
00144 $this->mExtra['lang'] = $wgLocalInterwiki;
00145
00146 if( !$wgPutIPinRC ) {
00147 $this->mAttribs['rc_ip'] = '';
00148 }
00149
00150 # If our database is strict about IP addresses, use NULL instead of an empty string
00151 if( $dbw->strictIPs() and $this->mAttribs['rc_ip'] == '' ) {
00152 unset( $this->mAttribs['rc_ip'] );
00153 }
00154
00155 # Fixup database timestamps
00156 $this->mAttribs['rc_timestamp'] = $dbw->timestamp($this->mAttribs['rc_timestamp']);
00157 $this->mAttribs['rc_cur_time'] = $dbw->timestamp($this->mAttribs['rc_cur_time']);
00158 $this->mAttribs['rc_id'] = $dbw->nextSequenceValue( 'recentchanges_rc_id_seq' );
00159
00160 ## If we are using foreign keys, an entry of 0 for the page_id will fail, so use NULL
00161 if( $dbw->cascadingDeletes() and $this->mAttribs['rc_cur_id']==0 ) {
00162 unset( $this->mAttribs['rc_cur_id'] );
00163 }
00164
00165 # Insert new row
00166 $dbw->insert( 'recentchanges', $this->mAttribs, $fname );
00167
00168 # Set the ID
00169 $this->mAttribs['rc_id'] = $dbw->insertId();
00170
00171 # Notify extensions
00172 wfRunHooks( 'RecentChange_save', array( &$this ) );
00173
00174 # Notify external application via UDP
00175 if( $wgRC2UDPAddress && ( !$this->mAttribs['rc_bot'] || !$wgRC2UDPOmitBots ) ) {
00176 self::sendToUDP( $this->getIRCLine() );
00177 }
00178
00179 # E-mail notifications
00180 global $wgUseEnotif, $wgShowUpdatedMarker, $wgUser;
00181 if( $wgUseEnotif || $wgShowUpdatedMarker ) {
00182
00183 if( $this->mAttribs['rc_user'] ) {
00184 $editor = ($wgUser->getId() == $this->mAttribs['rc_user']) ?
00185 $wgUser : User::newFromID( $this->mAttribs['rc_user'] );
00186
00187 } else {
00188 $editor = ($wgUser->getName() == $this->mAttribs['rc_user_text']) ?
00189 $wgUser : User::newFromName( $this->mAttribs['rc_user_text'], false );
00190 }
00191 # FIXME: this would be better as an extension hook
00192 $enotif = new EmailNotification();
00193 $title = Title::makeTitle( $this->mAttribs['rc_namespace'], $this->mAttribs['rc_title'] );
00194 $enotif->notifyOnPageChange( $editor, $title,
00195 $this->mAttribs['rc_timestamp'],
00196 $this->mAttribs['rc_comment'],
00197 $this->mAttribs['rc_minor'],
00198 $this->mAttribs['rc_last_oldid'] );
00199 }
00200 }
00201
00202 public function notifyRC2UDP() {
00203 global $wgRC2UDPAddress, $wgRC2UDPOmitBots;
00204 # Notify external application via UDP
00205 if( $wgRC2UDPAddress && ( !$this->mAttribs['rc_bot'] || !$wgRC2UDPOmitBots ) ) {
00206 self::sendToUDP( $this->getIRCLine() );
00207 }
00208 }
00209
00217 public static function sendToUDP( $line, $address = '', $prefix = '' ) {
00218 global $wgRC2UDPAddress, $wgRC2UDPPrefix, $wgRC2UDPPort;
00219 # Assume default for standard RC case
00220 $address = $address ? $address : $wgRC2UDPAddress;
00221 $prefix = $prefix ? $prefix : $wgRC2UDPPrefix;
00222 # Notify external application via UDP
00223 if( $address ) {
00224 $conn = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
00225 if( $conn ) {
00226 $line = $prefix . $line;
00227 wfDebug( __METHOD__ . ": sending UDP line: $line\n" );
00228 socket_sendto( $conn, $line, strlen($line), 0, $address, $wgRC2UDPPort );
00229 socket_close( $conn );
00230 return true;
00231 } else {
00232 wfDebug( __METHOD__ . ": failed to create UDP socket\n" );
00233 }
00234 }
00235 return false;
00236 }
00237
00243 public static function cleanupForIRC( $text ) {
00244 return Sanitizer::decodeCharReferences( str_replace( array( "\n", "\r" ), array( "", "" ), $text ) );
00245 }
00246
00254 public static function markPatrolled( $change, $auto = false ) {
00255 $change = $change instanceof RecentChange
00256 ? $change
00257 : RecentChange::newFromId($change);
00258 if( !$change instanceof RecentChange ) {
00259 return null;
00260 }
00261 return $change->doMarkPatrolled( $auto );
00262 }
00263
00271 public function doMarkPatrolled( $auto = false ) {
00272 global $wgUser, $wgUseRCPatrol, $wgUseNPPatrol;
00273 $errors = array();
00274
00275
00276 if( !$wgUseRCPatrol && ( !$wgUseNPPatrol || $this->getAttribute('rc_type') != RC_NEW ) ) {
00277 $errors[] = array('rcpatroldisabled');
00278 }
00279
00280 $right = $auto ? 'autopatrol' : 'patrol';
00281 $errors = array_merge( $errors, $this->getTitle()->getUserPermissionsErrors( $right, $wgUser ) );
00282 if( !wfRunHooks('MarkPatrolled', array($this->getAttribute('rc_id'), &$wgUser, false)) ) {
00283 $errors[] = array('hookaborted');
00284 }
00285
00286
00287 if( $wgUser->getName() == $this->getAttribute('rc_user_text') && !$wgUser->isAllowed('autopatrol') ) {
00288 $errors[] = array('markedaspatrollederror-noautopatrol');
00289 }
00290 if( $errors ) {
00291 return $errors;
00292 }
00293
00294 if( $this->getAttribute('rc_patrolled') ) {
00295 return array();
00296 }
00297
00298 $this->reallyMarkPatrolled();
00299
00300 PatrolLog::record( $this, $auto );
00301 wfRunHooks( 'MarkPatrolledComplete', array($this->getAttribute('rc_id'), &$wgUser, false) );
00302 return array();
00303 }
00304
00309 public function reallyMarkPatrolled() {
00310 $dbw = wfGetDB( DB_MASTER );
00311 $dbw->update(
00312 'recentchanges',
00313 array(
00314 'rc_patrolled' => 1
00315 ),
00316 array(
00317 'rc_id' => $this->getAttribute('rc_id')
00318 ),
00319 __METHOD__
00320 );
00321 return $dbw->affectedRows();
00322 }
00323
00324 # Makes an entry in the database corresponding to an edit
00325 public static function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, $oldId,
00326 $lastTimestamp, $bot, $ip='', $oldSize=0, $newSize=0, $newId=0, $patrol=0 )
00327 {
00328 if( !$ip ) {
00329 $ip = wfGetIP();
00330 if( !$ip ) $ip = '';
00331 }
00332
00333 $rc = new RecentChange;
00334 $rc->mAttribs = array(
00335 'rc_timestamp' => $timestamp,
00336 'rc_cur_time' => $timestamp,
00337 'rc_namespace' => $title->getNamespace(),
00338 'rc_title' => $title->getDBkey(),
00339 'rc_type' => RC_EDIT,
00340 'rc_minor' => $minor ? 1 : 0,
00341 'rc_cur_id' => $title->getArticleID(),
00342 'rc_user' => $user->getId(),
00343 'rc_user_text' => $user->getName(),
00344 'rc_comment' => $comment,
00345 'rc_this_oldid' => $newId,
00346 'rc_last_oldid' => $oldId,
00347 'rc_bot' => $bot ? 1 : 0,
00348 'rc_moved_to_ns' => 0,
00349 'rc_moved_to_title' => '',
00350 'rc_ip' => $ip,
00351 'rc_patrolled' => intval($patrol),
00352 'rc_new' => 0, # obsolete
00353 'rc_old_len' => $oldSize,
00354 'rc_new_len' => $newSize,
00355 'rc_deleted' => 0,
00356 'rc_logid' => 0,
00357 'rc_log_type' => null,
00358 'rc_log_action' => '',
00359 'rc_params' => ''
00360 );
00361
00362 $rc->mExtra = array(
00363 'prefixedDBkey' => $title->getPrefixedDBkey(),
00364 'lastTimestamp' => $lastTimestamp,
00365 'oldSize' => $oldSize,
00366 'newSize' => $newSize,
00367 );
00368 $rc->save();
00369 return $rc;
00370 }
00371
00377 public static function notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot,
00378 $ip='', $size=0, $newId=0, $patrol=0 )
00379 {
00380 if( !$ip ) {
00381 $ip = wfGetIP();
00382 if( !$ip ) $ip = '';
00383 }
00384
00385 $rc = new RecentChange;
00386 $rc->mAttribs = array(
00387 'rc_timestamp' => $timestamp,
00388 'rc_cur_time' => $timestamp,
00389 'rc_namespace' => $title->getNamespace(),
00390 'rc_title' => $title->getDBkey(),
00391 'rc_type' => RC_NEW,
00392 'rc_minor' => $minor ? 1 : 0,
00393 'rc_cur_id' => $title->getArticleID(),
00394 'rc_user' => $user->getId(),
00395 'rc_user_text' => $user->getName(),
00396 'rc_comment' => $comment,
00397 'rc_this_oldid' => $newId,
00398 'rc_last_oldid' => 0,
00399 'rc_bot' => $bot ? 1 : 0,
00400 'rc_moved_to_ns' => 0,
00401 'rc_moved_to_title' => '',
00402 'rc_ip' => $ip,
00403 'rc_patrolled' => intval($patrol),
00404 'rc_new' => 1, # obsolete
00405 'rc_old_len' => 0,
00406 'rc_new_len' => $size,
00407 'rc_deleted' => 0,
00408 'rc_logid' => 0,
00409 'rc_log_type' => null,
00410 'rc_log_action' => '',
00411 'rc_params' => ''
00412 );
00413
00414 $rc->mExtra = array(
00415 'prefixedDBkey' => $title->getPrefixedDBkey(),
00416 'lastTimestamp' => 0,
00417 'oldSize' => 0,
00418 'newSize' => $size
00419 );
00420 $rc->save();
00421 return $rc;
00422 }
00423
00424 # Makes an entry in the database corresponding to a rename
00425 public static function notifyMove( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='', $overRedir = false )
00426 {
00427 global $wgRequest;
00428 if( !$ip ) {
00429 $ip = wfGetIP();
00430 if( !$ip ) $ip = '';
00431 }
00432
00433 $rc = new RecentChange;
00434 $rc->mAttribs = array(
00435 'rc_timestamp' => $timestamp,
00436 'rc_cur_time' => $timestamp,
00437 'rc_namespace' => $oldTitle->getNamespace(),
00438 'rc_title' => $oldTitle->getDBkey(),
00439 'rc_type' => $overRedir ? RC_MOVE_OVER_REDIRECT : RC_MOVE,
00440 'rc_minor' => 0,
00441 'rc_cur_id' => $oldTitle->getArticleID(),
00442 'rc_user' => $user->getId(),
00443 'rc_user_text' => $user->getName(),
00444 'rc_comment' => $comment,
00445 'rc_this_oldid' => 0,
00446 'rc_last_oldid' => 0,
00447 'rc_bot' => $user->isAllowed( 'bot' ) ? $wgRequest->getBool( 'bot' , true ) : 0,
00448 'rc_moved_to_ns' => $newTitle->getNamespace(),
00449 'rc_moved_to_title' => $newTitle->getDBkey(),
00450 'rc_ip' => $ip,
00451 'rc_new' => 0, # obsolete
00452 'rc_patrolled' => 1,
00453 'rc_old_len' => null,
00454 'rc_new_len' => null,
00455 'rc_deleted' => 0,
00456 'rc_logid' => 0, # notifyMove not used anymore
00457 'rc_log_type' => null,
00458 'rc_log_action' => '',
00459 'rc_params' => ''
00460 );
00461
00462 $rc->mExtra = array(
00463 'prefixedDBkey' => $oldTitle->getPrefixedDBkey(),
00464 'lastTimestamp' => 0,
00465 'prefixedMoveTo' => $newTitle->getPrefixedDBkey()
00466 );
00467 $rc->save();
00468 }
00469
00470 public static function notifyMoveToNew( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='' ) {
00471 RecentChange::notifyMove( $timestamp, $oldTitle, $newTitle, $user, $comment, $ip, false );
00472 }
00473
00474 public static function notifyMoveOverRedirect( $timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip='' ) {
00475 RecentChange::notifyMove( $timestamp, $oldTitle, $newTitle, $user, $comment, $ip, true );
00476 }
00477
00478 public static function notifyLog( $timestamp, &$title, &$user, $actionComment, $ip='', $type,
00479 $action, $target, $logComment, $params, $newId=0 )
00480 {
00481 global $wgLogRestrictions;
00482 # Don't add private logs to RC!
00483 if( isset($wgLogRestrictions[$type]) && $wgLogRestrictions[$type] != '*' ) {
00484 return false;
00485 }
00486 $rc = self::newLogEntry( $timestamp, $title, $user, $actionComment, $ip, $type, $action,
00487 $target, $logComment, $params, $newId );
00488 $rc->save();
00489 return true;
00490 }
00491
00492 public static function newLogEntry( $timestamp, &$title, &$user, $actionComment, $ip='',
00493 $type, $action, $target, $logComment, $params, $newId=0 )
00494 {
00495 global $wgRequest;
00496 if( !$ip ) {
00497 $ip = wfGetIP();
00498 if( !$ip ) $ip = '';
00499 }
00500
00501 $rc = new RecentChange;
00502 $rc->mAttribs = array(
00503 'rc_timestamp' => $timestamp,
00504 'rc_cur_time' => $timestamp,
00505 'rc_namespace' => $target->getNamespace(),
00506 'rc_title' => $target->getDBkey(),
00507 'rc_type' => RC_LOG,
00508 'rc_minor' => 0,
00509 'rc_cur_id' => $target->getArticleID(),
00510 'rc_user' => $user->getId(),
00511 'rc_user_text' => $user->getName(),
00512 'rc_comment' => $logComment,
00513 'rc_this_oldid' => 0,
00514 'rc_last_oldid' => 0,
00515 'rc_bot' => $user->isAllowed( 'bot' ) ? $wgRequest->getBool( 'bot', true ) : 0,
00516 'rc_moved_to_ns' => 0,
00517 'rc_moved_to_title' => '',
00518 'rc_ip' => $ip,
00519 'rc_patrolled' => 1,
00520 'rc_new' => 0, # obsolete
00521 'rc_old_len' => null,
00522 'rc_new_len' => null,
00523 'rc_deleted' => 0,
00524 'rc_logid' => $newId,
00525 'rc_log_type' => $type,
00526 'rc_log_action' => $action,
00527 'rc_params' => $params
00528 );
00529 $rc->mExtra = array(
00530 'prefixedDBkey' => $title->getPrefixedDBkey(),
00531 'lastTimestamp' => 0,
00532 'actionComment' => $actionComment,
00533 );
00534 return $rc;
00535 }
00536
00537 # Initialises the members of this object from a mysql row object
00538 public function loadFromRow( $row ) {
00539 $this->mAttribs = get_object_vars( $row );
00540 $this->mAttribs['rc_timestamp'] = wfTimestamp(TS_MW, $this->mAttribs['rc_timestamp']);
00541 $this->mAttribs['rc_deleted'] = $row->rc_deleted;
00542 }
00543
00544 # Makes a pseudo-RC entry from a cur row
00545 public function loadFromCurRow( $row ) {
00546 $this->mAttribs = array(
00547 'rc_timestamp' => wfTimestamp(TS_MW, $row->rev_timestamp),
00548 'rc_cur_time' => $row->rev_timestamp,
00549 'rc_user' => $row->rev_user,
00550 'rc_user_text' => $row->rev_user_text,
00551 'rc_namespace' => $row->page_namespace,
00552 'rc_title' => $row->page_title,
00553 'rc_comment' => $row->rev_comment,
00554 'rc_minor' => $row->rev_minor_edit ? 1 : 0,
00555 'rc_type' => $row->page_is_new ? RC_NEW : RC_EDIT,
00556 'rc_cur_id' => $row->page_id,
00557 'rc_this_oldid' => $row->rev_id,
00558 'rc_last_oldid' => isset($row->rc_last_oldid) ? $row->rc_last_oldid : 0,
00559 'rc_bot' => 0,
00560 'rc_moved_to_ns' => 0,
00561 'rc_moved_to_title' => '',
00562 'rc_ip' => '',
00563 'rc_id' => $row->rc_id,
00564 'rc_patrolled' => $row->rc_patrolled,
00565 'rc_new' => $row->page_is_new, # obsolete
00566 'rc_old_len' => $row->rc_old_len,
00567 'rc_new_len' => $row->rc_new_len,
00568 'rc_params' => isset($row->rc_params) ? $row->rc_params : '',
00569 'rc_log_type' => isset($row->rc_log_type) ? $row->rc_log_type : null,
00570 'rc_log_action' => isset($row->rc_log_action) ? $row->rc_log_action : null,
00571 'rc_log_id' => isset($row->rc_log_id) ? $row->rc_log_id: 0,
00572 'rc_deleted' => $row->rc_deleted
00573 );
00574 }
00575
00582 public function getAttribute( $name ) {
00583 return isset( $this->mAttribs[$name] ) ? $this->mAttribs[$name] : null;
00584 }
00585
00586 public function getAttributes() {
00587 return $this->mAttribs;
00588 }
00589
00594 public function diffLinkTrail( $forceCur ) {
00595 if( $this->mAttribs['rc_type'] == RC_EDIT ) {
00596 $trail = "curid=" . (int)($this->mAttribs['rc_cur_id']) .
00597 "&oldid=" . (int)($this->mAttribs['rc_last_oldid']);
00598 if( $forceCur ) {
00599 $trail .= '&diff=0' ;
00600 } else {
00601 $trail .= '&diff=' . (int)($this->mAttribs['rc_this_oldid']);
00602 }
00603 } else {
00604 $trail = '';
00605 }
00606 return $trail;
00607 }
00608
00609 public function getIRCLine() {
00610 global $wgUseRCPatrol, $wgUseNPPatrol, $wgRC2UDPInterwikiPrefix, $wgLocalInterwiki;
00611
00612
00613
00614 extract($this->mAttribs);
00615 extract($this->mExtra);
00616
00617 if( $rc_type == RC_LOG ) {
00618 $titleObj = Title::newFromText( "Log/$rc_log_type", NS_SPECIAL );
00619 } else {
00620 $titleObj =& $this->getTitle();
00621 }
00622 $title = $titleObj->getPrefixedText();
00623 $title = self::cleanupForIRC( $title );
00624
00625 if( $rc_type == RC_LOG ) {
00626 $url = '';
00627 } else {
00628 if( $rc_type == RC_NEW ) {
00629 $url = "oldid=$rc_this_oldid";
00630 } else {
00631 $url = "diff=$rc_this_oldid&oldid=$rc_last_oldid";
00632 }
00633 if( $wgUseRCPatrol || ($rc_type == RC_NEW && $wgUseNPPatrol) ) {
00634 $url .= "&rcid=$rc_id";
00635 }
00636
00637
00638
00639
00640 $url = preg_replace( '/title=[^&]*&/', '', $titleObj->getInternalURL( $url ) );
00641 }
00642
00643 if( isset( $oldSize ) && isset( $newSize ) ) {
00644 $szdiff = $newSize - $oldSize;
00645 if($szdiff < -500) {
00646 $szdiff = "\002$szdiff\002";
00647 } elseif($szdiff >= 0) {
00648 $szdiff = '+' . $szdiff ;
00649 }
00650 $szdiff = '(' . $szdiff . ')' ;
00651 } else {
00652 $szdiff = '';
00653 }
00654
00655 $user = self::cleanupForIRC( $rc_user_text );
00656
00657 if( $rc_type == RC_LOG ) {
00658 $targetText = $this->getTitle()->getPrefixedText();
00659 $comment = self::cleanupForIRC( str_replace("[[$targetText]]","[[\00302$targetText\00310]]",$actionComment) );
00660 $flag = $rc_log_action;
00661 } else {
00662 $comment = self::cleanupForIRC( $rc_comment );
00663 $flag = '';
00664 if( !$rc_patrolled && ($wgUseRCPatrol || $rc_new && $wgUseNPPatrol) ) {
00665 $flag .= '!';
00666 }
00667 $flag .= ($rc_new ? "N" : "") . ($rc_minor ? "M" : "") . ($rc_bot ? "B" : "");
00668 }
00669
00670 if ( $wgRC2UDPInterwikiPrefix === true ) {
00671 $prefix = $wgLocalInterwiki;
00672 } elseif ( $wgRC2UDPInterwikiPrefix ) {
00673 $prefix = $wgRC2UDPInterwikiPrefix;
00674 } else {
00675 $prefix = false;
00676 }
00677 if ( $prefix !== false ) {
00678 $titleString = "\00314[[\00303$prefix:\00307$title\00314]]";
00679 } else {
00680 $titleString = "\00314[[\00307$title\00314]]";
00681 }
00682
00683 # see http://www.irssi.org/documentation/formats for some colour codes. prefix is \003,
00684 # no colour (\003) switches back to the term default
00685 $fullString = "$titleString\0034 $flag\00310 " .
00686 "\00302$url\003 \0035*\003 \00303$user\003 \0035*\003 $szdiff \00310$comment\003\n";
00687
00688 return $fullString;
00689 }
00690
00695 public function getCharacterDifference( $old = 0, $new = 0 ) {
00696 if( $old === 0 ) {
00697 $old = $this->mAttribs['rc_old_len'];
00698 }
00699 if( $new === 0 ) {
00700 $new = $this->mAttribs['rc_new_len'];
00701 }
00702 if( $old === null || $new === null ) {
00703 return '';
00704 }
00705 return ChangesList::showCharacterDifference( $old, $new );
00706 }
00707 }