[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Contain classes for dealing with individual log entries 4 * 5 * This is how I see the log system history: 6 * - appending to plain wiki pages 7 * - formatting log entries based on database fields 8 * - user is now part of the action message 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with this program; if not, write to the Free Software Foundation, Inc., 22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 23 * http://www.gnu.org/copyleft/gpl.html 24 * 25 * @file 26 * @author Niklas Laxström 27 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later 28 * @since 1.19 29 */ 30 31 /** 32 * Interface for log entries. Every log entry has these methods. 33 * @since 1.19 34 */ 35 interface LogEntry { 36 /** 37 * The main log type. 38 * @return string 39 */ 40 public function getType(); 41 42 /** 43 * The log subtype. 44 * @return string 45 */ 46 public function getSubtype(); 47 48 /** 49 * The full logtype in format maintype/subtype. 50 * @return string 51 */ 52 public function getFullType(); 53 54 /** 55 * Get the extra parameters stored for this message. 56 * @return array 57 */ 58 public function getParameters(); 59 60 /** 61 * Get the user for performed this action. 62 * @return User 63 */ 64 public function getPerformer(); 65 66 /** 67 * Get the target page of this action. 68 * @return Title 69 */ 70 public function getTarget(); 71 72 /** 73 * Get the timestamp when the action was executed. 74 * @return string 75 */ 76 public function getTimestamp(); 77 78 /** 79 * Get the user provided comment. 80 * @return string 81 */ 82 public function getComment(); 83 84 /** 85 * Get the access restriction. 86 * @return string 87 */ 88 public function getDeleted(); 89 90 /** 91 * @param int $field One of LogPage::DELETED_* bitfield constants 92 * @return bool 93 */ 94 public function isDeleted( $field ); 95 } 96 97 /** 98 * Extends the LogEntryInterface with some basic functionality 99 * @since 1.19 100 */ 101 abstract class LogEntryBase implements LogEntry { 102 public function getFullType() { 103 return $this->getType() . '/' . $this->getSubtype(); 104 } 105 106 public function isDeleted( $field ) { 107 return ( $this->getDeleted() & $field ) === $field; 108 } 109 110 /** 111 * Whether the parameters for this log are stored in new or 112 * old format. 113 * @return bool 114 */ 115 public function isLegacy() { 116 return false; 117 } 118 } 119 120 /** 121 * This class wraps around database result row. 122 * @since 1.19 123 */ 124 class DatabaseLogEntry extends LogEntryBase { 125 // Static-> 126 127 /** 128 * Returns array of information that is needed for querying 129 * log entries. Array contains the following keys: 130 * tables, fields, conds, options and join_conds 131 * @return array 132 */ 133 public static function getSelectQueryData() { 134 $tables = array( 'logging', 'user' ); 135 $fields = array( 136 'log_id', 'log_type', 'log_action', 'log_timestamp', 137 'log_user', 'log_user_text', 138 'log_namespace', 'log_title', // unused log_page 139 'log_comment', 'log_params', 'log_deleted', 140 'user_id', 'user_name', 'user_editcount', 141 ); 142 143 $joins = array( 144 // IP's don't have an entry in user table 145 'user' => array( 'LEFT JOIN', 'log_user=user_id' ), 146 ); 147 148 return array( 149 'tables' => $tables, 150 'fields' => $fields, 151 'conds' => array(), 152 'options' => array(), 153 'join_conds' => $joins, 154 ); 155 } 156 157 /** 158 * Constructs new LogEntry from database result row. 159 * Supports rows from both logging and recentchanges table. 160 * @param stdClass|array $row 161 * @return DatabaseLogEntry 162 */ 163 public static function newFromRow( $row ) { 164 $row = (object)$row; 165 if ( isset( $row->rc_logid ) ) { 166 return new RCDatabaseLogEntry( $row ); 167 } else { 168 return new self( $row ); 169 } 170 } 171 172 // Non-static-> 173 174 /** @var stdClass Database result row. */ 175 protected $row; 176 177 /** @var User */ 178 protected $performer; 179 180 /** @var bool Whether the parameters for this log entry are stored in new 181 * or old format. 182 */ 183 protected $legacy; 184 185 protected function __construct( $row ) { 186 $this->row = $row; 187 } 188 189 /** 190 * Returns the unique database id. 191 * @return int 192 */ 193 public function getId() { 194 return (int)$this->row->log_id; 195 } 196 197 /** 198 * Returns whatever is stored in the database field. 199 * @return string 200 */ 201 protected function getRawParameters() { 202 return $this->row->log_params; 203 } 204 205 // LogEntryBase-> 206 207 public function isLegacy() { 208 // This does the check 209 $this->getParameters(); 210 211 return $this->legacy; 212 } 213 214 // LogEntry-> 215 216 public function getType() { 217 return $this->row->log_type; 218 } 219 220 public function getSubtype() { 221 return $this->row->log_action; 222 } 223 224 public function getParameters() { 225 if ( !isset( $this->params ) ) { 226 $blob = $this->getRawParameters(); 227 wfSuppressWarnings(); 228 $params = unserialize( $blob ); 229 wfRestoreWarnings(); 230 if ( $params !== false ) { 231 $this->params = $params; 232 $this->legacy = false; 233 } else { 234 $this->params = $blob === '' ? array() : explode( "\n", $blob ); 235 $this->legacy = true; 236 } 237 } 238 239 return $this->params; 240 } 241 242 public function getPerformer() { 243 if ( !$this->performer ) { 244 $userId = (int)$this->row->log_user; 245 if ( $userId !== 0 ) { // logged-in users 246 if ( isset( $this->row->user_name ) ) { 247 $this->performer = User::newFromRow( $this->row ); 248 } else { 249 $this->performer = User::newFromId( $userId ); 250 } 251 } else { // IP users 252 $userText = $this->row->log_user_text; 253 $this->performer = User::newFromName( $userText, false ); 254 } 255 } 256 257 return $this->performer; 258 } 259 260 public function getTarget() { 261 $namespace = $this->row->log_namespace; 262 $page = $this->row->log_title; 263 $title = Title::makeTitle( $namespace, $page ); 264 265 return $title; 266 } 267 268 public function getTimestamp() { 269 return wfTimestamp( TS_MW, $this->row->log_timestamp ); 270 } 271 272 public function getComment() { 273 return $this->row->log_comment; 274 } 275 276 public function getDeleted() { 277 return $this->row->log_deleted; 278 } 279 } 280 281 class RCDatabaseLogEntry extends DatabaseLogEntry { 282 283 public function getId() { 284 return $this->row->rc_logid; 285 } 286 287 protected function getRawParameters() { 288 return $this->row->rc_params; 289 } 290 291 // LogEntry-> 292 293 public function getType() { 294 return $this->row->rc_log_type; 295 } 296 297 public function getSubtype() { 298 return $this->row->rc_log_action; 299 } 300 301 public function getPerformer() { 302 if ( !$this->performer ) { 303 $userId = (int)$this->row->rc_user; 304 if ( $userId !== 0 ) { 305 $this->performer = User::newFromId( $userId ); 306 } else { 307 $userText = $this->row->rc_user_text; 308 // Might be an IP, don't validate the username 309 $this->performer = User::newFromName( $userText, false ); 310 } 311 } 312 313 return $this->performer; 314 } 315 316 public function getTarget() { 317 $namespace = $this->row->rc_namespace; 318 $page = $this->row->rc_title; 319 $title = Title::makeTitle( $namespace, $page ); 320 321 return $title; 322 } 323 324 public function getTimestamp() { 325 return wfTimestamp( TS_MW, $this->row->rc_timestamp ); 326 } 327 328 public function getComment() { 329 return $this->row->rc_comment; 330 } 331 332 public function getDeleted() { 333 return $this->row->rc_deleted; 334 } 335 } 336 337 /** 338 * Class for creating log entries manually, for 339 * example to inject them into the database. 340 * @since 1.19 341 */ 342 class ManualLogEntry extends LogEntryBase { 343 /** @var string Type of log entry */ 344 protected $type; 345 346 /** @var string Sub type of log entry */ 347 protected $subtype; 348 349 /** @var array Parameters for log entry */ 350 protected $parameters = array(); 351 352 /** @var array */ 353 protected $relations = array(); 354 355 /** @var User Performer of the action for the log entry */ 356 protected $performer; 357 358 /** @var Title Target title for the log entry */ 359 protected $target; 360 361 /** @var string Timestamp of creation of the log entry */ 362 protected $timestamp; 363 364 /** @var string Comment for the log entry */ 365 protected $comment = ''; 366 367 /** @var int Deletion state of the log entry */ 368 protected $deleted; 369 370 /** @var int ID of the log entry */ 371 protected $id; 372 373 /** 374 * Constructor. 375 * 376 * @since 1.19 377 * 378 * @param string $type 379 * @param string $subtype 380 */ 381 public function __construct( $type, $subtype ) { 382 $this->type = $type; 383 $this->subtype = $subtype; 384 } 385 386 /** 387 * Set extra log parameters. 388 * You can pass params to the log action message 389 * by prefixing the keys with a number and colon. 390 * The numbering should start with number 4, the 391 * first three parameters are hardcoded for every 392 * message. Example: 393 * $entry->setParameters( 394 * '4:color' => 'blue', 395 * 'animal' => 'dog' 396 * ); 397 * 398 * @since 1.19 399 * 400 * @param array $parameters Associative array 401 */ 402 public function setParameters( $parameters ) { 403 $this->parameters = $parameters; 404 } 405 406 /** 407 * Declare arbitrary tag/value relations to this log entry. 408 * These can be used to filter log entries later on. 409 * 410 * @param array $relations Map of (tag => (list of values|value)) 411 * @since 1.22 412 */ 413 public function setRelations( array $relations ) { 414 $this->relations = $relations; 415 } 416 417 /** 418 * Set the user that performed the action being logged. 419 * 420 * @since 1.19 421 * 422 * @param User $performer 423 */ 424 public function setPerformer( User $performer ) { 425 $this->performer = $performer; 426 } 427 428 /** 429 * Set the title of the object changed. 430 * 431 * @since 1.19 432 * 433 * @param Title $target 434 */ 435 public function setTarget( Title $target ) { 436 $this->target = $target; 437 } 438 439 /** 440 * Set the timestamp of when the logged action took place. 441 * 442 * @since 1.19 443 * 444 * @param string $timestamp 445 */ 446 public function setTimestamp( $timestamp ) { 447 $this->timestamp = $timestamp; 448 } 449 450 /** 451 * Set a comment associated with the action being logged. 452 * 453 * @since 1.19 454 * 455 * @param string $comment 456 */ 457 public function setComment( $comment ) { 458 $this->comment = $comment; 459 } 460 461 /** 462 * TODO: document 463 * 464 * @since 1.19 465 * 466 * @param int $deleted 467 */ 468 public function setDeleted( $deleted ) { 469 $this->deleted = $deleted; 470 } 471 472 /** 473 * Inserts the entry into the logging table. 474 * @param IDatabase $dbw 475 * @return int ID of the log entry 476 * @throws MWException 477 */ 478 public function insert( IDatabase $dbw = null ) { 479 global $wgContLang; 480 481 $dbw = $dbw ?: wfGetDB( DB_MASTER ); 482 $id = $dbw->nextSequenceValue( 'logging_log_id_seq' ); 483 484 if ( $this->timestamp === null ) { 485 $this->timestamp = wfTimestampNow(); 486 } 487 488 # Trim spaces on user supplied text 489 $comment = trim( $this->getComment() ); 490 491 # Truncate for whole multibyte characters. 492 $comment = $wgContLang->truncate( $comment, 255 ); 493 494 $data = array( 495 'log_id' => $id, 496 'log_type' => $this->getType(), 497 'log_action' => $this->getSubtype(), 498 'log_timestamp' => $dbw->timestamp( $this->getTimestamp() ), 499 'log_user' => $this->getPerformer()->getId(), 500 'log_user_text' => $this->getPerformer()->getName(), 501 'log_namespace' => $this->getTarget()->getNamespace(), 502 'log_title' => $this->getTarget()->getDBkey(), 503 'log_page' => $this->getTarget()->getArticleID(), 504 'log_comment' => $comment, 505 'log_params' => serialize( (array)$this->getParameters() ), 506 ); 507 if ( isset( $this->deleted ) ) { 508 $data['log_deleted'] = $this->deleted; 509 } 510 511 $dbw->insert( 'logging', $data, __METHOD__ ); 512 $this->id = !is_null( $id ) ? $id : $dbw->insertId(); 513 514 $rows = array(); 515 foreach ( $this->relations as $tag => $values ) { 516 if ( !strlen( $tag ) ) { 517 throw new MWException( "Got empty log search tag." ); 518 } 519 520 if ( !is_array( $values ) ) { 521 $values = array( $values ); 522 } 523 524 foreach ( $values as $value ) { 525 $rows[] = array( 526 'ls_field' => $tag, 527 'ls_value' => $value, 528 'ls_log_id' => $this->id 529 ); 530 } 531 } 532 if ( count( $rows ) ) { 533 $dbw->insert( 'log_search', $rows, __METHOD__, 'IGNORE' ); 534 } 535 536 // Update any bloom filter cache 537 $member = $this->getTarget()->getNamespace() . ':' . $this->getTarget()->getDBkey(); 538 BloomCache::get( 'main' )->insert( wfWikiId(), 'TitleHasLogs', $member ); 539 540 return $this->id; 541 } 542 543 /** 544 * Get a RecentChanges object for the log entry 545 * @param int $newId 546 * @return RecentChange 547 * @since 1.23 548 */ 549 public function getRecentChange( $newId = 0 ) { 550 $formatter = LogFormatter::newFromEntry( $this ); 551 $context = RequestContext::newExtraneousContext( $this->getTarget() ); 552 $formatter->setContext( $context ); 553 554 $logpage = SpecialPage::getTitleFor( 'Log', $this->getType() ); 555 $user = $this->getPerformer(); 556 $ip = ""; 557 if ( $user->isAnon() ) { 558 /* 559 * "MediaWiki default" and friends may have 560 * no IP address in their name 561 */ 562 if ( IP::isIPAddress( $user->getName() ) ) { 563 $ip = $user->getName(); 564 } 565 } 566 567 return RecentChange::newLogEntry( 568 $this->getTimestamp(), 569 $logpage, 570 $user, 571 $formatter->getPlainActionText(), 572 $ip, 573 $this->getType(), 574 $this->getSubtype(), 575 $this->getTarget(), 576 $this->getComment(), 577 serialize( (array)$this->getParameters() ), 578 $newId, 579 $formatter->getIRCActionComment() // Used for IRC feeds 580 ); 581 } 582 583 /** 584 * Publishes the log entry. 585 * @param int $newId Id of the log entry. 586 * @param string $to One of: rcandudp (default), rc, udp 587 */ 588 public function publish( $newId, $to = 'rcandudp' ) { 589 $log = new LogPage( $this->getType() ); 590 if ( $log->isRestricted() ) { 591 return; 592 } 593 594 $rc = $this->getRecentChange( $newId ); 595 596 if ( $to === 'rc' || $to === 'rcandudp' ) { 597 $rc->save( 'pleasedontudp' ); 598 } 599 600 if ( $to === 'udp' || $to === 'rcandudp' ) { 601 $rc->notifyRCFeeds(); 602 } 603 } 604 605 // LogEntry-> 606 607 public function getType() { 608 return $this->type; 609 } 610 611 public function getSubtype() { 612 return $this->subtype; 613 } 614 615 public function getParameters() { 616 return $this->parameters; 617 } 618 619 /** 620 * @return User 621 */ 622 public function getPerformer() { 623 return $this->performer; 624 } 625 626 /** 627 * @return Title 628 */ 629 public function getTarget() { 630 return $this->target; 631 } 632 633 public function getTimestamp() { 634 $ts = $this->timestamp !== null ? $this->timestamp : wfTimestampNow(); 635 636 return wfTimestamp( TS_MW, $ts ); 637 } 638 639 public function getComment() { 640 return $this->comment; 641 } 642 643 public function getDeleted() { 644 return (int)$this->deleted; 645 } 646 }
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 |