MediaWiki
REL1_23
|
00001 <?php 00032 class LogPage { 00033 const DELETED_ACTION = 1; 00034 const DELETED_COMMENT = 2; 00035 const DELETED_USER = 4; 00036 const DELETED_RESTRICTED = 8; 00037 00038 // Convenience fields 00039 const SUPPRESSED_USER = 12; 00040 const SUPPRESSED_ACTION = 9; 00041 00043 public $updateRecentChanges; 00044 00046 public $sendToUDP; 00047 00049 private $ircActionText; 00050 00052 private $actionText; 00053 00057 private $type; 00058 00061 private $action; 00062 00064 private $comment; 00065 00067 private $params; 00068 00070 private $doer; 00071 00073 private $target; 00074 00083 public function __construct( $type, $rc = true, $udp = 'skipUDP' ) { 00084 $this->type = $type; 00085 $this->updateRecentChanges = $rc; 00086 $this->sendToUDP = ( $udp == 'UDP' ); 00087 } 00088 00092 protected function saveContent() { 00093 global $wgLogRestrictions; 00094 00095 $dbw = wfGetDB( DB_MASTER ); 00096 $log_id = $dbw->nextSequenceValue( 'logging_log_id_seq' ); 00097 00098 // @todo FIXME private/protected/public property? 00099 $this->timestamp = $now = wfTimestampNow(); 00100 $data = array( 00101 'log_id' => $log_id, 00102 'log_type' => $this->type, 00103 'log_action' => $this->action, 00104 'log_timestamp' => $dbw->timestamp( $now ), 00105 'log_user' => $this->doer->getId(), 00106 'log_user_text' => $this->doer->getName(), 00107 'log_namespace' => $this->target->getNamespace(), 00108 'log_title' => $this->target->getDBkey(), 00109 'log_page' => $this->target->getArticleID(), 00110 'log_comment' => $this->comment, 00111 'log_params' => $this->params 00112 ); 00113 $dbw->insert( 'logging', $data, __METHOD__ ); 00114 $newId = !is_null( $log_id ) ? $log_id : $dbw->insertId(); 00115 00116 # And update recentchanges 00117 if ( $this->updateRecentChanges ) { 00118 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); 00119 00120 RecentChange::notifyLog( 00121 $now, $titleObj, $this->doer, $this->getRcComment(), '', 00122 $this->type, $this->action, $this->target, $this->comment, 00123 $this->params, $newId, $this->getRcCommentIRC() 00124 ); 00125 } elseif ( $this->sendToUDP ) { 00126 # Don't send private logs to UDP 00127 if ( isset( $wgLogRestrictions[$this->type] ) && $wgLogRestrictions[$this->type] != '*' ) { 00128 return $newId; 00129 } 00130 00131 # Notify external application via UDP. 00132 # We send this to IRC but do not want to add it the RC table. 00133 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); 00134 $rc = RecentChange::newLogEntry( 00135 $now, $titleObj, $this->doer, $this->getRcComment(), '', 00136 $this->type, $this->action, $this->target, $this->comment, 00137 $this->params, $newId, $this->getRcCommentIRC() 00138 ); 00139 $rc->notifyRCFeeds(); 00140 } 00141 00142 return $newId; 00143 } 00144 00150 public function getRcComment() { 00151 $rcComment = $this->actionText; 00152 00153 if ( $this->comment != '' ) { 00154 if ( $rcComment == '' ) { 00155 $rcComment = $this->comment; 00156 } else { 00157 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . 00158 $this->comment; 00159 } 00160 } 00161 00162 return $rcComment; 00163 } 00164 00170 public function getRcCommentIRC() { 00171 $rcComment = $this->ircActionText; 00172 00173 if ( $this->comment != '' ) { 00174 if ( $rcComment == '' ) { 00175 $rcComment = $this->comment; 00176 } else { 00177 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . 00178 $this->comment; 00179 } 00180 } 00181 00182 return $rcComment; 00183 } 00184 00188 public function getComment() { 00189 return $this->comment; 00190 } 00191 00197 public static function validTypes() { 00198 global $wgLogTypes; 00199 00200 return $wgLogTypes; 00201 } 00202 00209 public static function isLogType( $type ) { 00210 return in_array( $type, LogPage::validTypes() ); 00211 } 00212 00220 public static function logName( $type ) { 00221 global $wgLogNames; 00222 00223 wfDeprecated( __METHOD__, '1.21' ); 00224 00225 if ( isset( $wgLogNames[$type] ) ) { 00226 return str_replace( '_', ' ', wfMessage( $wgLogNames[$type] )->text() ); 00227 } else { 00228 // Bogus log types? Perhaps an extension was removed. 00229 return $type; 00230 } 00231 } 00232 00241 public static function logHeader( $type ) { 00242 global $wgLogHeaders; 00243 00244 wfDeprecated( __METHOD__, '1.21' ); 00245 00246 return wfMessage( $wgLogHeaders[$type] )->parse(); 00247 } 00248 00262 public static function actionText( $type, $action, $title = null, $skin = null, 00263 $params = array(), $filterWikilinks = false 00264 ) { 00265 global $wgLang, $wgContLang, $wgLogActions; 00266 00267 if ( is_null( $skin ) ) { 00268 $langObj = $wgContLang; 00269 $langObjOrNull = null; 00270 } else { 00271 $langObj = $wgLang; 00272 $langObjOrNull = $wgLang; 00273 } 00274 00275 $key = "$type/$action"; 00276 00277 if ( isset( $wgLogActions[$key] ) ) { 00278 if ( is_null( $title ) ) { 00279 $rv = wfMessage( $wgLogActions[$key] )->inLanguage( $langObj )->escaped(); 00280 } else { 00281 $titleLink = self::getTitleLink( $type, $langObjOrNull, $title, $params ); 00282 00283 if ( count( $params ) == 0 ) { 00284 $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink ) 00285 ->inLanguage( $langObj )->escaped(); 00286 } else { 00287 $details = ''; 00288 array_unshift( $params, $titleLink ); 00289 00290 // User suppression 00291 if ( preg_match( '/^(block|suppress)\/(block|reblock)$/', $key ) ) { 00292 if ( $skin ) { 00293 // Localize the duration, and add a tooltip 00294 // in English to help visitors from other wikis. 00295 // The lrm is needed to make sure that the number 00296 // is shown on the correct side of the tooltip text. 00297 $durationTooltip = '‎' . htmlspecialchars( $params[1] ); 00298 $params[1] = "<span class='blockExpiry' title='$durationTooltip'>" . 00299 $wgLang->translateBlockExpiry( $params[1] ) . '</span>'; 00300 } else { 00301 $params[1] = $wgContLang->translateBlockExpiry( $params[1] ); 00302 } 00303 00304 $params[2] = isset( $params[2] ) ? 00305 self::formatBlockFlags( $params[2], $langObj ) : ''; 00306 // Page protections 00307 } elseif ( $type == 'protect' && count( $params ) == 3 ) { 00308 // Restrictions and expiries 00309 if ( $skin ) { 00310 $details .= $wgLang->getDirMark() . htmlspecialchars( " {$params[1]}" ); 00311 } else { 00312 $details .= " {$params[1]}"; 00313 } 00314 00315 // Cascading flag... 00316 if ( $params[2] ) { 00317 $text = wfMessage( 'protect-summary-cascade' ) 00318 ->inLanguage( $langObj )->text(); 00319 $details .= ' '; 00320 $details .= wfMessage( 'brackets', $text )->inLanguage( $langObj )->text(); 00321 00322 } 00323 } 00324 00325 $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params ) 00326 ->inLanguage( $langObj )->escaped() . $details; 00327 } 00328 } 00329 } else { 00330 global $wgLogActionsHandlers; 00331 00332 if ( isset( $wgLogActionsHandlers[$key] ) ) { 00333 $args = func_get_args(); 00334 $rv = call_user_func_array( $wgLogActionsHandlers[$key], $args ); 00335 } else { 00336 wfDebug( "LogPage::actionText - unknown action $key\n" ); 00337 $rv = "$action"; 00338 } 00339 } 00340 00341 // For the perplexed, this feature was added in r7855 by Erik. 00342 // The feature was added because we liked adding [[$1]] in our log entries 00343 // but the log entries are parsed as Wikitext on RecentChanges but as HTML 00344 // on Special:Log. The hack is essentially that [[$1]] represented a link 00345 // to the title in question. The first parameter to the HTML version (Special:Log) 00346 // is that link in HTML form, and so this just gets rid of the ugly [[]]. 00347 // However, this is a horrible hack and it doesn't work like you expect if, say, 00348 // you want to link to something OTHER than the title of the log entry. 00349 // The real problem, which Erik was trying to fix (and it sort-of works now) is 00350 // that the same messages are being treated as both wikitext *and* HTML. 00351 if ( $filterWikilinks ) { 00352 $rv = str_replace( '[[', '', $rv ); 00353 $rv = str_replace( ']]', '', $rv ); 00354 } 00355 00356 return $rv; 00357 } 00358 00367 protected static function getTitleLink( $type, $lang, $title, &$params ) { 00368 if ( !$lang ) { 00369 return $title->getPrefixedText(); 00370 } 00371 00372 switch ( $type ) { 00373 case 'move': 00374 $titleLink = Linker::link( 00375 $title, 00376 htmlspecialchars( $title->getPrefixedText() ), 00377 array(), 00378 array( 'redirect' => 'no' ) 00379 ); 00380 00381 $targetTitle = Title::newFromText( $params[0] ); 00382 00383 if ( !$targetTitle ) { 00384 # Workaround for broken database 00385 $params[0] = htmlspecialchars( $params[0] ); 00386 } else { 00387 $params[0] = Linker::link( 00388 $targetTitle, 00389 htmlspecialchars( $params[0] ) 00390 ); 00391 } 00392 break; 00393 case 'block': 00394 if ( substr( $title->getText(), 0, 1 ) == '#' ) { 00395 $titleLink = $title->getText(); 00396 } else { 00397 // @todo Store the user identifier in the parameters 00398 // to make this faster for future log entries 00399 $id = User::idFromName( $title->getText() ); 00400 $titleLink = Linker::userLink( $id, $title->getText() ) 00401 . Linker::userToolLinks( $id, $title->getText(), false, Linker::TOOL_LINKS_NOBLOCK ); 00402 } 00403 break; 00404 case 'merge': 00405 $titleLink = Linker::link( 00406 $title, 00407 $title->getPrefixedText(), 00408 array(), 00409 array( 'redirect' => 'no' ) 00410 ); 00411 $params[0] = Linker::link( 00412 Title::newFromText( $params[0] ), 00413 htmlspecialchars( $params[0] ) 00414 ); 00415 $params[1] = $lang->timeanddate( $params[1] ); 00416 break; 00417 default: 00418 if ( $title->isSpecialPage() ) { 00419 list( $name, $par ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); 00420 00421 # Use the language name for log titles, rather than Log/X 00422 if ( $name == 'Log' ) { 00423 $logPage = new LogPage( $par ); 00424 $titleLink = Linker::link( $title, $logPage->getName()->escaped() ); 00425 $titleLink = wfMessage( 'parentheses' ) 00426 ->inLanguage( $lang ) 00427 ->rawParams( $titleLink ) 00428 ->escaped(); 00429 } else { 00430 $titleLink = Linker::link( $title ); 00431 } 00432 } else { 00433 $titleLink = Linker::link( $title ); 00434 } 00435 } 00436 00437 return $titleLink; 00438 } 00439 00452 public function addEntry( $action, $target, $comment, $params = array(), $doer = null ) { 00453 global $wgContLang; 00454 00455 if ( !is_array( $params ) ) { 00456 $params = array( $params ); 00457 } 00458 00459 if ( $comment === null ) { 00460 $comment = ''; 00461 } 00462 00463 # Trim spaces on user supplied text 00464 $comment = trim( $comment ); 00465 00466 # Truncate for whole multibyte characters. 00467 $comment = $wgContLang->truncate( $comment, 255 ); 00468 00469 $this->action = $action; 00470 $this->target = $target; 00471 $this->comment = $comment; 00472 $this->params = LogPage::makeParamBlob( $params ); 00473 00474 if ( $doer === null ) { 00475 global $wgUser; 00476 $doer = $wgUser; 00477 } elseif ( !is_object( $doer ) ) { 00478 $doer = User::newFromId( $doer ); 00479 } 00480 00481 $this->doer = $doer; 00482 00483 $logEntry = new ManualLogEntry( $this->type, $action ); 00484 $logEntry->setTarget( $target ); 00485 $logEntry->setPerformer( $doer ); 00486 $logEntry->setParameters( $params ); 00487 00488 $formatter = LogFormatter::newFromEntry( $logEntry ); 00489 $context = RequestContext::newExtraneousContext( $target ); 00490 $formatter->setContext( $context ); 00491 00492 $this->actionText = $formatter->getPlainActionText(); 00493 $this->ircActionText = $formatter->getIRCActionText(); 00494 00495 return $this->saveContent(); 00496 } 00497 00506 public function addRelations( $field, $values, $logid ) { 00507 if ( !strlen( $field ) || empty( $values ) ) { 00508 return false; // nothing 00509 } 00510 00511 $data = array(); 00512 00513 foreach ( $values as $value ) { 00514 $data[] = array( 00515 'ls_field' => $field, 00516 'ls_value' => $value, 00517 'ls_log_id' => $logid 00518 ); 00519 } 00520 00521 $dbw = wfGetDB( DB_MASTER ); 00522 $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' ); 00523 00524 return true; 00525 } 00526 00533 public static function makeParamBlob( $params ) { 00534 return implode( "\n", $params ); 00535 } 00536 00543 public static function extractParams( $blob ) { 00544 if ( $blob === '' ) { 00545 return array(); 00546 } else { 00547 return explode( "\n", $blob ); 00548 } 00549 } 00550 00559 public static function formatBlockFlags( $flags, $lang ) { 00560 $flags = trim( $flags ); 00561 if ( $flags === '' ) { 00562 return ''; //nothing to do 00563 } 00564 $flags = explode( ',', $flags ); 00565 $flagsCount = count( $flags ); 00566 00567 for ( $i = 0; $i < $flagsCount; $i++ ) { 00568 $flags[$i] = self::formatBlockFlag( $flags[$i], $lang ); 00569 } 00570 00571 return wfMessage( 'parentheses' )->inLanguage( $lang ) 00572 ->rawParams( $lang->commaList( $flags ) )->escaped(); 00573 } 00574 00582 public static function formatBlockFlag( $flag, $lang ) { 00583 static $messages = array(); 00584 00585 if ( !isset( $messages[$flag] ) ) { 00586 $messages[$flag] = htmlspecialchars( $flag ); // Fallback 00587 00588 // For grepping. The following core messages can be used here: 00589 // * block-log-flags-angry-autoblock 00590 // * block-log-flags-anononly 00591 // * block-log-flags-hiddenname 00592 // * block-log-flags-noautoblock 00593 // * block-log-flags-nocreate 00594 // * block-log-flags-noemail 00595 // * block-log-flags-nousertalk 00596 $msg = wfMessage( 'block-log-flags-' . $flag )->inLanguage( $lang ); 00597 00598 if ( $msg->exists() ) { 00599 $messages[$flag] = $msg->escaped(); 00600 } 00601 } 00602 00603 return $messages[$flag]; 00604 } 00605 00611 public function getName() { 00612 global $wgLogNames; 00613 00614 // BC 00615 if ( isset( $wgLogNames[$this->type] ) ) { 00616 $key = $wgLogNames[$this->type]; 00617 } else { 00618 $key = 'log-name-' . $this->type; 00619 } 00620 00621 return wfMessage( $key ); 00622 } 00623 00629 public function getDescription() { 00630 global $wgLogHeaders; 00631 // BC 00632 if ( isset( $wgLogHeaders[$this->type] ) ) { 00633 $key = $wgLogHeaders[$this->type]; 00634 } else { 00635 $key = 'log-description-' . $this->type; 00636 } 00637 00638 return wfMessage( $key ); 00639 } 00640 00646 public function getRestriction() { 00647 global $wgLogRestrictions; 00648 if ( isset( $wgLogRestrictions[$this->type] ) ) { 00649 $restriction = $wgLogRestrictions[$this->type]; 00650 } else { 00651 // '' always returns true with $user->isAllowed() 00652 $restriction = ''; 00653 } 00654 00655 return $restriction; 00656 } 00657 00663 public function isRestricted() { 00664 $restriction = $this->getRestriction(); 00665 00666 return $restriction !== '' && $restriction !== '*'; 00667 } 00668 }