[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Utility class for creating and accessing recent change entries. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 */ 22 23 /** 24 * Utility class for creating new RC entries 25 * 26 * mAttribs: 27 * rc_id id of the row in the recentchanges table 28 * rc_timestamp time the entry was made 29 * rc_namespace namespace # 30 * rc_title non-prefixed db key 31 * rc_type is new entry, used to determine whether updating is necessary 32 * rc_source string representation of change source 33 * rc_minor is minor 34 * rc_cur_id page_id of associated page entry 35 * rc_user user id who made the entry 36 * rc_user_text user name who made the entry 37 * rc_comment edit summary 38 * rc_this_oldid rev_id associated with this entry (or zero) 39 * rc_last_oldid rev_id associated with the entry before this one (or zero) 40 * rc_bot is bot, hidden 41 * rc_ip IP address of the user in dotted quad notation 42 * rc_new obsolete, use rc_type==RC_NEW 43 * rc_patrolled boolean whether or not someone has marked this edit as patrolled 44 * rc_old_len integer byte length of the text before the edit 45 * rc_new_len the same after the edit 46 * rc_deleted partial deletion 47 * rc_logid the log_id value for this log entry (or zero) 48 * rc_log_type the log type (or null) 49 * rc_log_action the log action (or null) 50 * rc_params log params 51 * 52 * mExtra: 53 * prefixedDBkey prefixed db key, used by external app via msg queue 54 * lastTimestamp timestamp of previous entry, used in WHERE clause during update 55 * oldSize text size before the change 56 * newSize text size after the change 57 * pageStatus status of the page: created, deleted, moved, restored, changed 58 * 59 * temporary: not stored in the database 60 * notificationtimestamp 61 * numberofWatchingusers 62 */ 63 class RecentChange { 64 // Constants for the rc_source field. Extensions may also have 65 // their own source constants. 66 const SRC_EDIT = 'mw.edit'; 67 const SRC_NEW = 'mw.new'; 68 const SRC_LOG = 'mw.log'; 69 const SRC_EXTERNAL = 'mw.external'; // obsolete 70 71 public $mAttribs = array(); 72 public $mExtra = array(); 73 74 /** 75 * @var Title 76 */ 77 public $mTitle = false; 78 79 /** 80 * @var User 81 */ 82 private $mPerformer = false; 83 84 public $numberofWatchingusers = 0; # Dummy to prevent error message in SpecialRecentChangesLinked 85 public $notificationtimestamp; 86 87 /** 88 * @var int Line number of recent change. Default -1. 89 */ 90 public $counter = -1; 91 92 # Factory methods 93 94 /** 95 * @param mixed $row 96 * @return RecentChange 97 */ 98 public static function newFromRow( $row ) { 99 $rc = new RecentChange; 100 $rc->loadFromRow( $row ); 101 102 return $rc; 103 } 104 105 /** 106 * Parsing text to RC_* constants 107 * @since 1.24 108 * @param string|array $type 109 * @throws MWException 110 * @return int|array RC_TYPE 111 */ 112 public static function parseToRCType( $type ) { 113 if ( is_array( $type ) ) { 114 $retval = array(); 115 foreach ( $type as $t ) { 116 $retval[] = RecentChange::parseToRCType( $t ); 117 } 118 119 return $retval; 120 } 121 122 switch ( $type ) { 123 case 'edit': 124 return RC_EDIT; 125 case 'new': 126 return RC_NEW; 127 case 'log': 128 return RC_LOG; 129 case 'external': 130 return RC_EXTERNAL; 131 default: 132 throw new MWException( "Unknown type '$type'" ); 133 } 134 } 135 136 /** 137 * Parsing RC_* constants to human-readable test 138 * @since 1.24 139 * @param int $rcType 140 * @return string $type 141 */ 142 public static function parseFromRCType( $rcType ) { 143 switch ( $rcType ) { 144 case RC_EDIT: 145 $type = 'edit'; 146 break; 147 case RC_NEW: 148 $type = 'new'; 149 break; 150 case RC_LOG: 151 $type = 'log'; 152 break; 153 case RC_EXTERNAL: 154 $type = 'external'; 155 break; 156 default: 157 $type = "$rcType"; 158 } 159 160 return $type; 161 } 162 163 /** 164 * Obtain the recent change with a given rc_id value 165 * 166 * @param int $rcid The rc_id value to retrieve 167 * @return RecentChange 168 */ 169 public static function newFromId( $rcid ) { 170 return self::newFromConds( array( 'rc_id' => $rcid ), __METHOD__ ); 171 } 172 173 /** 174 * Find the first recent change matching some specific conditions 175 * 176 * @param array $conds Array of conditions 177 * @param mixed $fname Override the method name in profiling/logs 178 * @param array $options Query options 179 * @return RecentChange 180 */ 181 public static function newFromConds( $conds, $fname = __METHOD__, $options = array() ) { 182 $dbr = wfGetDB( DB_SLAVE ); 183 $row = $dbr->selectRow( 'recentchanges', self::selectFields(), $conds, $fname, $options ); 184 if ( $row !== false ) { 185 return self::newFromRow( $row ); 186 } else { 187 return null; 188 } 189 } 190 191 /** 192 * Return the list of recentchanges fields that should be selected to create 193 * a new recentchanges object. 194 * @return array 195 */ 196 public static function selectFields() { 197 return array( 198 'rc_id', 199 'rc_timestamp', 200 'rc_user', 201 'rc_user_text', 202 'rc_namespace', 203 'rc_title', 204 'rc_comment', 205 'rc_minor', 206 'rc_bot', 207 'rc_new', 208 'rc_cur_id', 209 'rc_this_oldid', 210 'rc_last_oldid', 211 'rc_type', 212 'rc_source', 213 'rc_patrolled', 214 'rc_ip', 215 'rc_old_len', 216 'rc_new_len', 217 'rc_deleted', 218 'rc_logid', 219 'rc_log_type', 220 'rc_log_action', 221 'rc_params', 222 ); 223 } 224 225 # Accessors 226 227 /** 228 * @param array $attribs 229 */ 230 public function setAttribs( $attribs ) { 231 $this->mAttribs = $attribs; 232 } 233 234 /** 235 * @param array $extra 236 */ 237 public function setExtra( $extra ) { 238 $this->mExtra = $extra; 239 } 240 241 /** 242 * @return Title 243 */ 244 public function &getTitle() { 245 if ( $this->mTitle === false ) { 246 $this->mTitle = Title::makeTitle( $this->mAttribs['rc_namespace'], $this->mAttribs['rc_title'] ); 247 } 248 249 return $this->mTitle; 250 } 251 252 /** 253 * Get the User object of the person who performed this change. 254 * 255 * @return User 256 */ 257 public function getPerformer() { 258 if ( $this->mPerformer === false ) { 259 if ( $this->mAttribs['rc_user'] ) { 260 $this->mPerformer = User::newFromID( $this->mAttribs['rc_user'] ); 261 } else { 262 $this->mPerformer = User::newFromName( $this->mAttribs['rc_user_text'], false ); 263 } 264 } 265 266 return $this->mPerformer; 267 } 268 269 /** 270 * Writes the data in this object to the database 271 * @param bool $noudp 272 */ 273 public function save( $noudp = false ) { 274 global $wgPutIPinRC, $wgUseEnotif, $wgShowUpdatedMarker, $wgContLang; 275 276 $dbw = wfGetDB( DB_MASTER ); 277 if ( !is_array( $this->mExtra ) ) { 278 $this->mExtra = array(); 279 } 280 281 if ( !$wgPutIPinRC ) { 282 $this->mAttribs['rc_ip'] = ''; 283 } 284 285 # If our database is strict about IP addresses, use NULL instead of an empty string 286 if ( $dbw->strictIPs() and $this->mAttribs['rc_ip'] == '' ) { 287 unset( $this->mAttribs['rc_ip'] ); 288 } 289 290 # Trim spaces on user supplied text 291 $this->mAttribs['rc_comment'] = trim( $this->mAttribs['rc_comment'] ); 292 293 # Make sure summary is truncated (whole multibyte characters) 294 $this->mAttribs['rc_comment'] = $wgContLang->truncate( $this->mAttribs['rc_comment'], 255 ); 295 296 # Fixup database timestamps 297 $this->mAttribs['rc_timestamp'] = $dbw->timestamp( $this->mAttribs['rc_timestamp'] ); 298 $this->mAttribs['rc_id'] = $dbw->nextSequenceValue( 'recentchanges_rc_id_seq' ); 299 300 ## If we are using foreign keys, an entry of 0 for the page_id will fail, so use NULL 301 if ( $dbw->cascadingDeletes() and $this->mAttribs['rc_cur_id'] == 0 ) { 302 unset( $this->mAttribs['rc_cur_id'] ); 303 } 304 305 # Insert new row 306 $dbw->insert( 'recentchanges', $this->mAttribs, __METHOD__ ); 307 308 # Set the ID 309 $this->mAttribs['rc_id'] = $dbw->insertId(); 310 311 # Notify extensions 312 wfRunHooks( 'RecentChange_save', array( &$this ) ); 313 314 # Notify external application via UDP 315 if ( !$noudp ) { 316 $this->notifyRCFeeds(); 317 } 318 319 # E-mail notifications 320 if ( $wgUseEnotif || $wgShowUpdatedMarker ) { 321 $editor = $this->getPerformer(); 322 $title = $this->getTitle(); 323 324 if ( wfRunHooks( 'AbortEmailNotification', array( $editor, $title, $this ) ) ) { 325 # @todo FIXME: This would be better as an extension hook 326 $enotif = new EmailNotification(); 327 $enotif->notifyOnPageChange( $editor, $title, 328 $this->mAttribs['rc_timestamp'], 329 $this->mAttribs['rc_comment'], 330 $this->mAttribs['rc_minor'], 331 $this->mAttribs['rc_last_oldid'], 332 $this->mExtra['pageStatus'] ); 333 } 334 } 335 } 336 337 /** 338 * Notify all the feeds about the change. 339 * @param array $feeds Optional feeds to send to, defaults to $wgRCFeeds 340 */ 341 public function notifyRCFeeds( array $feeds = null ) { 342 global $wgRCFeeds; 343 if ( $feeds === null ) { 344 $feeds = $wgRCFeeds; 345 } 346 347 $performer = $this->getPerformer(); 348 349 foreach ( $feeds as $feed ) { 350 $feed += array( 351 'omit_bots' => false, 352 'omit_anon' => false, 353 'omit_user' => false, 354 'omit_minor' => false, 355 'omit_patrolled' => false, 356 ); 357 358 if ( 359 ( $feed['omit_bots'] && $this->mAttribs['rc_bot'] ) || 360 ( $feed['omit_anon'] && $performer->isAnon() ) || 361 ( $feed['omit_user'] && !$performer->isAnon() ) || 362 ( $feed['omit_minor'] && $this->mAttribs['rc_minor'] ) || 363 ( $feed['omit_patrolled'] && $this->mAttribs['rc_patrolled'] ) || 364 $this->mAttribs['rc_type'] == RC_EXTERNAL 365 ) { 366 continue; 367 } 368 369 $engine = self::getEngine( $feed['uri'] ); 370 371 if ( isset( $this->mExtra['actionCommentIRC'] ) ) { 372 $actionComment = $this->mExtra['actionCommentIRC']; 373 } else { 374 $actionComment = null; 375 } 376 377 /** @var $formatter RCFeedFormatter */ 378 $formatter = is_object( $feed['formatter'] ) ? $feed['formatter'] : new $feed['formatter'](); 379 $line = $formatter->getLine( $feed, $this, $actionComment ); 380 381 $engine->send( $feed, $line ); 382 } 383 } 384 385 /** 386 * Gets the stream engine object for a given URI from $wgRCEngines 387 * 388 * @param string $uri URI to get the engine object for 389 * @throws MWException 390 * @return RCFeedEngine The engine object 391 */ 392 public static function getEngine( $uri ) { 393 global $wgRCEngines; 394 395 $scheme = parse_url( $uri, PHP_URL_SCHEME ); 396 if ( !$scheme ) { 397 throw new MWException( __FUNCTION__ . ": Invalid stream logger URI: '$uri'" ); 398 } 399 400 if ( !isset( $wgRCEngines[$scheme] ) ) { 401 throw new MWException( __FUNCTION__ . ": Unknown stream logger URI scheme: $scheme" ); 402 } 403 404 return new $wgRCEngines[$scheme]; 405 } 406 407 /** 408 * Mark a given change as patrolled 409 * 410 * @param RecentChange|int $change RecentChange or corresponding rc_id 411 * @param bool $auto For automatic patrol 412 * @return array See doMarkPatrolled(), or null if $change is not an existing rc_id 413 */ 414 public static function markPatrolled( $change, $auto = false ) { 415 global $wgUser; 416 417 $change = $change instanceof RecentChange 418 ? $change 419 : RecentChange::newFromId( $change ); 420 421 if ( !$change instanceof RecentChange ) { 422 return null; 423 } 424 425 return $change->doMarkPatrolled( $wgUser, $auto ); 426 } 427 428 /** 429 * Mark this RecentChange as patrolled 430 * 431 * NOTE: Can also return 'rcpatroldisabled', 'hookaborted' and 432 * 'markedaspatrollederror-noautopatrol' as errors 433 * @param User $user User object doing the action 434 * @param bool $auto For automatic patrol 435 * @return array Array of permissions errors, see Title::getUserPermissionsErrors() 436 */ 437 public function doMarkPatrolled( User $user, $auto = false ) { 438 global $wgUseRCPatrol, $wgUseNPPatrol; 439 $errors = array(); 440 // If recentchanges patrol is disabled, only new pages 441 // can be patrolled 442 if ( !$wgUseRCPatrol && ( !$wgUseNPPatrol || $this->getAttribute( 'rc_type' ) != RC_NEW ) ) { 443 $errors[] = array( 'rcpatroldisabled' ); 444 } 445 // Automatic patrol needs "autopatrol", ordinary patrol needs "patrol" 446 $right = $auto ? 'autopatrol' : 'patrol'; 447 $errors = array_merge( $errors, $this->getTitle()->getUserPermissionsErrors( $right, $user ) ); 448 if ( !wfRunHooks( 'MarkPatrolled', array( $this->getAttribute( 'rc_id' ), &$user, false ) ) ) { 449 $errors[] = array( 'hookaborted' ); 450 } 451 // Users without the 'autopatrol' right can't patrol their 452 // own revisions 453 if ( $user->getName() == $this->getAttribute( 'rc_user_text' ) 454 && !$user->isAllowed( 'autopatrol' ) 455 ) { 456 $errors[] = array( 'markedaspatrollederror-noautopatrol' ); 457 } 458 if ( $errors ) { 459 return $errors; 460 } 461 // If the change was patrolled already, do nothing 462 if ( $this->getAttribute( 'rc_patrolled' ) ) { 463 return array(); 464 } 465 // Actually set the 'patrolled' flag in RC 466 $this->reallyMarkPatrolled(); 467 // Log this patrol event 468 PatrolLog::record( $this, $auto, $user ); 469 wfRunHooks( 'MarkPatrolledComplete', array( $this->getAttribute( 'rc_id' ), &$user, false ) ); 470 471 return array(); 472 } 473 474 /** 475 * Mark this RecentChange patrolled, without error checking 476 * @return int Number of affected rows 477 */ 478 public function reallyMarkPatrolled() { 479 $dbw = wfGetDB( DB_MASTER ); 480 $dbw->update( 481 'recentchanges', 482 array( 483 'rc_patrolled' => 1 484 ), 485 array( 486 'rc_id' => $this->getAttribute( 'rc_id' ) 487 ), 488 __METHOD__ 489 ); 490 // Invalidate the page cache after the page has been patrolled 491 // to make sure that the Patrol link isn't visible any longer! 492 $this->getTitle()->invalidateCache(); 493 494 return $dbw->affectedRows(); 495 } 496 497 /** 498 * Makes an entry in the database corresponding to an edit 499 * 500 * @param string $timestamp 501 * @param Title $title 502 * @param bool $minor 503 * @param User $user 504 * @param string $comment 505 * @param int $oldId 506 * @param string $lastTimestamp 507 * @param bool $bot 508 * @param string $ip 509 * @param int $oldSize 510 * @param int $newSize 511 * @param int $newId 512 * @param int $patrol 513 * @return RecentChange 514 */ 515 public static function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, $oldId, 516 $lastTimestamp, $bot, $ip = '', $oldSize = 0, $newSize = 0, $newId = 0, $patrol = 0 ) { 517 $rc = new RecentChange; 518 $rc->mTitle = $title; 519 $rc->mPerformer = $user; 520 $rc->mAttribs = array( 521 'rc_timestamp' => $timestamp, 522 'rc_namespace' => $title->getNamespace(), 523 'rc_title' => $title->getDBkey(), 524 'rc_type' => RC_EDIT, 525 'rc_source' => self::SRC_EDIT, 526 'rc_minor' => $minor ? 1 : 0, 527 'rc_cur_id' => $title->getArticleID(), 528 'rc_user' => $user->getId(), 529 'rc_user_text' => $user->getName(), 530 'rc_comment' => $comment, 531 'rc_this_oldid' => $newId, 532 'rc_last_oldid' => $oldId, 533 'rc_bot' => $bot ? 1 : 0, 534 'rc_ip' => self::checkIPAddress( $ip ), 535 'rc_patrolled' => intval( $patrol ), 536 'rc_new' => 0, # obsolete 537 'rc_old_len' => $oldSize, 538 'rc_new_len' => $newSize, 539 'rc_deleted' => 0, 540 'rc_logid' => 0, 541 'rc_log_type' => null, 542 'rc_log_action' => '', 543 'rc_params' => '' 544 ); 545 546 $rc->mExtra = array( 547 'prefixedDBkey' => $title->getPrefixedDBkey(), 548 'lastTimestamp' => $lastTimestamp, 549 'oldSize' => $oldSize, 550 'newSize' => $newSize, 551 'pageStatus' => 'changed' 552 ); 553 $rc->save(); 554 555 return $rc; 556 } 557 558 /** 559 * Makes an entry in the database corresponding to page creation 560 * Note: the title object must be loaded with the new id using resetArticleID() 561 * 562 * @param string $timestamp 563 * @param Title $title 564 * @param bool $minor 565 * @param User $user 566 * @param string $comment 567 * @param bool $bot 568 * @param string $ip 569 * @param int $size 570 * @param int $newId 571 * @param int $patrol 572 * @return RecentChange 573 */ 574 public static function notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot, 575 $ip = '', $size = 0, $newId = 0, $patrol = 0 ) { 576 $rc = new RecentChange; 577 $rc->mTitle = $title; 578 $rc->mPerformer = $user; 579 $rc->mAttribs = array( 580 'rc_timestamp' => $timestamp, 581 'rc_namespace' => $title->getNamespace(), 582 'rc_title' => $title->getDBkey(), 583 'rc_type' => RC_NEW, 584 'rc_source' => self::SRC_NEW, 585 'rc_minor' => $minor ? 1 : 0, 586 'rc_cur_id' => $title->getArticleID(), 587 'rc_user' => $user->getId(), 588 'rc_user_text' => $user->getName(), 589 'rc_comment' => $comment, 590 'rc_this_oldid' => $newId, 591 'rc_last_oldid' => 0, 592 'rc_bot' => $bot ? 1 : 0, 593 'rc_ip' => self::checkIPAddress( $ip ), 594 'rc_patrolled' => intval( $patrol ), 595 'rc_new' => 1, # obsolete 596 'rc_old_len' => 0, 597 'rc_new_len' => $size, 598 'rc_deleted' => 0, 599 'rc_logid' => 0, 600 'rc_log_type' => null, 601 'rc_log_action' => '', 602 'rc_params' => '' 603 ); 604 605 $rc->mExtra = array( 606 'prefixedDBkey' => $title->getPrefixedDBkey(), 607 'lastTimestamp' => 0, 608 'oldSize' => 0, 609 'newSize' => $size, 610 'pageStatus' => 'created' 611 ); 612 $rc->save(); 613 614 return $rc; 615 } 616 617 /** 618 * @param string $timestamp 619 * @param Title $title 620 * @param User $user 621 * @param string $actionComment 622 * @param string $ip 623 * @param string $type 624 * @param string $action 625 * @param Title $target 626 * @param string $logComment 627 * @param string $params 628 * @param int $newId 629 * @param string $actionCommentIRC 630 * @return bool 631 */ 632 public static function notifyLog( $timestamp, &$title, &$user, $actionComment, $ip, $type, 633 $action, $target, $logComment, $params, $newId = 0, $actionCommentIRC = '' 634 ) { 635 global $wgLogRestrictions; 636 637 # Don't add private logs to RC! 638 if ( isset( $wgLogRestrictions[$type] ) && $wgLogRestrictions[$type] != '*' ) { 639 return false; 640 } 641 $rc = self::newLogEntry( $timestamp, $title, $user, $actionComment, $ip, $type, $action, 642 $target, $logComment, $params, $newId, $actionCommentIRC ); 643 $rc->save(); 644 645 return true; 646 } 647 648 /** 649 * @param string $timestamp 650 * @param Title $title 651 * @param User $user 652 * @param string $actionComment 653 * @param string $ip 654 * @param string $type 655 * @param string $action 656 * @param Title $target 657 * @param string $logComment 658 * @param string $params 659 * @param int $newId 660 * @param string $actionCommentIRC 661 * @return RecentChange 662 */ 663 public static function newLogEntry( $timestamp, &$title, &$user, $actionComment, $ip, 664 $type, $action, $target, $logComment, $params, $newId = 0, $actionCommentIRC = '' ) { 665 global $wgRequest; 666 667 ## Get pageStatus for email notification 668 switch ( $type . '-' . $action ) { 669 case 'delete-delete': 670 $pageStatus = 'deleted'; 671 break; 672 case 'move-move': 673 case 'move-move_redir': 674 $pageStatus = 'moved'; 675 break; 676 case 'delete-restore': 677 $pageStatus = 'restored'; 678 break; 679 case 'upload-upload': 680 $pageStatus = 'created'; 681 break; 682 case 'upload-overwrite': 683 default: 684 $pageStatus = 'changed'; 685 break; 686 } 687 688 $rc = new RecentChange; 689 $rc->mTitle = $target; 690 $rc->mPerformer = $user; 691 $rc->mAttribs = array( 692 'rc_timestamp' => $timestamp, 693 'rc_namespace' => $target->getNamespace(), 694 'rc_title' => $target->getDBkey(), 695 'rc_type' => RC_LOG, 696 'rc_source' => self::SRC_LOG, 697 'rc_minor' => 0, 698 'rc_cur_id' => $target->getArticleID(), 699 'rc_user' => $user->getId(), 700 'rc_user_text' => $user->getName(), 701 'rc_comment' => $logComment, 702 'rc_this_oldid' => 0, 703 'rc_last_oldid' => 0, 704 'rc_bot' => $user->isAllowed( 'bot' ) ? $wgRequest->getBool( 'bot', true ) : 0, 705 'rc_ip' => self::checkIPAddress( $ip ), 706 'rc_patrolled' => 1, 707 'rc_new' => 0, # obsolete 708 'rc_old_len' => null, 709 'rc_new_len' => null, 710 'rc_deleted' => 0, 711 'rc_logid' => $newId, 712 'rc_log_type' => $type, 713 'rc_log_action' => $action, 714 'rc_params' => $params 715 ); 716 717 $rc->mExtra = array( 718 'prefixedDBkey' => $title->getPrefixedDBkey(), 719 'lastTimestamp' => 0, 720 'actionComment' => $actionComment, // the comment appended to the action, passed from LogPage 721 'pageStatus' => $pageStatus, 722 'actionCommentIRC' => $actionCommentIRC 723 ); 724 725 return $rc; 726 } 727 728 /** 729 * Initialises the members of this object from a mysql row object 730 * 731 * @param mixed $row 732 */ 733 public function loadFromRow( $row ) { 734 $this->mAttribs = get_object_vars( $row ); 735 $this->mAttribs['rc_timestamp'] = wfTimestamp( TS_MW, $this->mAttribs['rc_timestamp'] ); 736 $this->mAttribs['rc_deleted'] = $row->rc_deleted; // MUST be set 737 } 738 739 /** 740 * Get an attribute value 741 * 742 * @param string $name Attribute name 743 * @return mixed 744 */ 745 public function getAttribute( $name ) { 746 return isset( $this->mAttribs[$name] ) ? $this->mAttribs[$name] : null; 747 } 748 749 /** 750 * @return array 751 */ 752 public function getAttributes() { 753 return $this->mAttribs; 754 } 755 756 /** 757 * Gets the end part of the diff URL associated with this object 758 * Blank if no diff link should be displayed 759 * @param bool $forceCur 760 * @return string 761 */ 762 public function diffLinkTrail( $forceCur ) { 763 if ( $this->mAttribs['rc_type'] == RC_EDIT ) { 764 $trail = "curid=" . (int)( $this->mAttribs['rc_cur_id'] ) . 765 "&oldid=" . (int)( $this->mAttribs['rc_last_oldid'] ); 766 if ( $forceCur ) { 767 $trail .= '&diff=0'; 768 } else { 769 $trail .= '&diff=' . (int)( $this->mAttribs['rc_this_oldid'] ); 770 } 771 } else { 772 $trail = ''; 773 } 774 775 return $trail; 776 } 777 778 /** 779 * Returns the change size (HTML). 780 * The lengths can be given optionally. 781 * @param int $old 782 * @param int $new 783 * @return string 784 */ 785 public function getCharacterDifference( $old = 0, $new = 0 ) { 786 if ( $old === 0 ) { 787 $old = $this->mAttribs['rc_old_len']; 788 } 789 if ( $new === 0 ) { 790 $new = $this->mAttribs['rc_new_len']; 791 } 792 if ( $old === null || $new === null ) { 793 return ''; 794 } 795 796 return ChangesList::showCharacterDifference( $old, $new ); 797 } 798 799 /** 800 * Purge expired changes from the recentchanges table 801 * @since 1.22 802 */ 803 public static function purgeExpiredChanges() { 804 if ( wfReadOnly() ) { 805 return; 806 } 807 808 $method = __METHOD__; 809 $dbw = wfGetDB( DB_MASTER ); 810 $dbw->onTransactionIdle( function () use ( $dbw, $method ) { 811 global $wgRCMaxAge; 812 813 $cutoff = $dbw->timestamp( time() - $wgRCMaxAge ); 814 $dbw->delete( 815 'recentchanges', 816 array( 'rc_timestamp < ' . $dbw->addQuotes( $cutoff ) ), 817 $method 818 ); 819 } ); 820 } 821 822 private static function checkIPAddress( $ip ) { 823 global $wgRequest; 824 if ( $ip ) { 825 if ( !IP::isIPAddress( $ip ) ) { 826 throw new MWException( "Attempt to write \"" . $ip . 827 "\" as an IP address into recent changes" ); 828 } 829 } else { 830 $ip = $wgRequest->getIP(); 831 if ( !$ip ) { 832 $ip = ''; 833 } 834 } 835 836 return $ip; 837 } 838 839 /** 840 * Check whether the given timestamp is new enough to have a RC row with a given tolerance 841 * as the recentchanges table might not be cleared out regularly (so older entries might exist) 842 * or rows which will be deleted soon shouldn't be included. 843 * 844 * @param mixed $timestamp MWTimestamp compatible timestamp 845 * @param int $tolerance Tolerance in seconds 846 * @return bool 847 */ 848 public static function isInRCLifespan( $timestamp, $tolerance = 0 ) { 849 global $wgRCMaxAge; 850 851 return wfTimestamp( TS_UNIX, $timestamp ) > time() - $tolerance - $wgRCMaxAge; 852 } 853 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |