MediaWiki
REL1_24
|
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 00189 public function getComment() { 00190 return $this->comment; 00191 } 00192 00198 public static function validTypes() { 00199 global $wgLogTypes; 00200 00201 return $wgLogTypes; 00202 } 00203 00210 public static function isLogType( $type ) { 00211 return in_array( $type, LogPage::validTypes() ); 00212 } 00213 00221 public static function logName( $type ) { 00222 global $wgLogNames; 00223 00224 wfDeprecated( __METHOD__, '1.21' ); 00225 00226 if ( isset( $wgLogNames[$type] ) ) { 00227 return str_replace( '_', ' ', wfMessage( $wgLogNames[$type] )->text() ); 00228 } else { 00229 // Bogus log types? Perhaps an extension was removed. 00230 return $type; 00231 } 00232 } 00233 00242 public static function logHeader( $type ) { 00243 global $wgLogHeaders; 00244 00245 wfDeprecated( __METHOD__, '1.21' ); 00246 00247 return wfMessage( $wgLogHeaders[$type] )->parse(); 00248 } 00249 00263 public static function actionText( $type, $action, $title = null, $skin = null, 00264 $params = array(), $filterWikilinks = false 00265 ) { 00266 global $wgLang, $wgContLang, $wgLogActions; 00267 00268 if ( is_null( $skin ) ) { 00269 $langObj = $wgContLang; 00270 $langObjOrNull = null; 00271 } else { 00272 $langObj = $wgLang; 00273 $langObjOrNull = $wgLang; 00274 } 00275 00276 $key = "$type/$action"; 00277 00278 if ( isset( $wgLogActions[$key] ) ) { 00279 if ( is_null( $title ) ) { 00280 $rv = wfMessage( $wgLogActions[$key] )->inLanguage( $langObj )->escaped(); 00281 } else { 00282 $titleLink = self::getTitleLink( $type, $langObjOrNull, $title, $params ); 00283 00284 if ( count( $params ) == 0 ) { 00285 $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink ) 00286 ->inLanguage( $langObj )->escaped(); 00287 } else { 00288 $details = ''; 00289 array_unshift( $params, $titleLink ); 00290 00291 // User suppression 00292 if ( preg_match( '/^(block|suppress)\/(block|reblock)$/', $key ) ) { 00293 if ( $skin ) { 00294 // Localize the duration, and add a tooltip 00295 // in English to help visitors from other wikis. 00296 // The lrm is needed to make sure that the number 00297 // is shown on the correct side of the tooltip text. 00298 $durationTooltip = '‎' . htmlspecialchars( $params[1] ); 00299 $params[1] = "<span class='blockExpiry' title='$durationTooltip'>" . 00300 $wgLang->translateBlockExpiry( $params[1] ) . '</span>'; 00301 } else { 00302 $params[1] = $wgContLang->translateBlockExpiry( $params[1] ); 00303 } 00304 00305 $params[2] = isset( $params[2] ) ? 00306 self::formatBlockFlags( $params[2], $langObj ) : ''; 00307 // Page protections 00308 } elseif ( $type == 'protect' && count( $params ) == 3 ) { 00309 // Restrictions and expiries 00310 if ( $skin ) { 00311 $details .= $wgLang->getDirMark() . htmlspecialchars( " {$params[1]}" ); 00312 } else { 00313 $details .= " {$params[1]}"; 00314 } 00315 00316 // Cascading flag... 00317 if ( $params[2] ) { 00318 $text = wfMessage( 'protect-summary-cascade' ) 00319 ->inLanguage( $langObj )->text(); 00320 $details .= ' '; 00321 $details .= wfMessage( 'brackets', $text )->inLanguage( $langObj )->text(); 00322 00323 } 00324 } 00325 00326 $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params ) 00327 ->inLanguage( $langObj )->escaped() . $details; 00328 } 00329 } 00330 } else { 00331 global $wgLogActionsHandlers; 00332 00333 if ( isset( $wgLogActionsHandlers[$key] ) ) { 00334 $args = func_get_args(); 00335 $rv = call_user_func_array( $wgLogActionsHandlers[$key], $args ); 00336 } else { 00337 wfDebug( "LogPage::actionText - unknown action $key\n" ); 00338 $rv = "$action"; 00339 } 00340 } 00341 00342 // For the perplexed, this feature was added in r7855 by Erik. 00343 // The feature was added because we liked adding [[$1]] in our log entries 00344 // but the log entries are parsed as Wikitext on RecentChanges but as HTML 00345 // on Special:Log. The hack is essentially that [[$1]] represented a link 00346 // to the title in question. The first parameter to the HTML version (Special:Log) 00347 // is that link in HTML form, and so this just gets rid of the ugly [[]]. 00348 // However, this is a horrible hack and it doesn't work like you expect if, say, 00349 // you want to link to something OTHER than the title of the log entry. 00350 // The real problem, which Erik was trying to fix (and it sort-of works now) is 00351 // that the same messages are being treated as both wikitext *and* HTML. 00352 if ( $filterWikilinks ) { 00353 $rv = str_replace( '[[', '', $rv ); 00354 $rv = str_replace( ']]', '', $rv ); 00355 } 00356 00357 return $rv; 00358 } 00359 00368 protected static function getTitleLink( $type, $lang, $title, &$params ) { 00369 if ( !$lang ) { 00370 return $title->getPrefixedText(); 00371 } 00372 00373 switch ( $type ) { 00374 case 'move': 00375 $titleLink = Linker::link( 00376 $title, 00377 htmlspecialchars( $title->getPrefixedText() ), 00378 array(), 00379 array( 'redirect' => 'no' ) 00380 ); 00381 00382 $targetTitle = Title::newFromText( $params[0] ); 00383 00384 if ( !$targetTitle ) { 00385 # Workaround for broken database 00386 $params[0] = htmlspecialchars( $params[0] ); 00387 } else { 00388 $params[0] = Linker::link( 00389 $targetTitle, 00390 htmlspecialchars( $params[0] ) 00391 ); 00392 } 00393 break; 00394 case 'block': 00395 if ( substr( $title->getText(), 0, 1 ) == '#' ) { 00396 $titleLink = $title->getText(); 00397 } else { 00398 // @todo Store the user identifier in the parameters 00399 // to make this faster for future log entries 00400 $id = User::idFromName( $title->getText() ); 00401 $titleLink = Linker::userLink( $id, $title->getText() ) 00402 . Linker::userToolLinks( $id, $title->getText(), false, Linker::TOOL_LINKS_NOBLOCK ); 00403 } 00404 break; 00405 case 'merge': 00406 $titleLink = Linker::link( 00407 $title, 00408 $title->getPrefixedText(), 00409 array(), 00410 array( 'redirect' => 'no' ) 00411 ); 00412 $params[0] = Linker::link( 00413 Title::newFromText( $params[0] ), 00414 htmlspecialchars( $params[0] ) 00415 ); 00416 $params[1] = $lang->timeanddate( $params[1] ); 00417 break; 00418 default: 00419 if ( $title->isSpecialPage() ) { 00420 list( $name, $par ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); 00421 00422 # Use the language name for log titles, rather than Log/X 00423 if ( $name == 'Log' ) { 00424 $logPage = new LogPage( $par ); 00425 $titleLink = Linker::link( $title, $logPage->getName()->escaped() ); 00426 $titleLink = wfMessage( 'parentheses' ) 00427 ->inLanguage( $lang ) 00428 ->rawParams( $titleLink ) 00429 ->escaped(); 00430 } else { 00431 $titleLink = Linker::link( $title ); 00432 } 00433 } else { 00434 $titleLink = Linker::link( $title ); 00435 } 00436 } 00437 00438 return $titleLink; 00439 } 00440 00453 public function addEntry( $action, $target, $comment, $params = array(), $doer = null ) { 00454 global $wgContLang; 00455 00456 if ( !is_array( $params ) ) { 00457 $params = array( $params ); 00458 } 00459 00460 if ( $comment === null ) { 00461 $comment = ''; 00462 } 00463 00464 # Trim spaces on user supplied text 00465 $comment = trim( $comment ); 00466 00467 # Truncate for whole multibyte characters. 00468 $comment = $wgContLang->truncate( $comment, 255 ); 00469 00470 $this->action = $action; 00471 $this->target = $target; 00472 $this->comment = $comment; 00473 $this->params = LogPage::makeParamBlob( $params ); 00474 00475 if ( $doer === null ) { 00476 global $wgUser; 00477 $doer = $wgUser; 00478 } elseif ( !is_object( $doer ) ) { 00479 $doer = User::newFromId( $doer ); 00480 } 00481 00482 $this->doer = $doer; 00483 00484 $logEntry = new ManualLogEntry( $this->type, $action ); 00485 $logEntry->setTarget( $target ); 00486 $logEntry->setPerformer( $doer ); 00487 $logEntry->setParameters( $params ); 00488 00489 $formatter = LogFormatter::newFromEntry( $logEntry ); 00490 $context = RequestContext::newExtraneousContext( $target ); 00491 $formatter->setContext( $context ); 00492 00493 $this->actionText = $formatter->getPlainActionText(); 00494 $this->ircActionText = $formatter->getIRCActionText(); 00495 00496 return $this->saveContent(); 00497 } 00498 00507 public function addRelations( $field, $values, $logid ) { 00508 if ( !strlen( $field ) || empty( $values ) ) { 00509 return false; // nothing 00510 } 00511 00512 $data = array(); 00513 00514 foreach ( $values as $value ) { 00515 $data[] = array( 00516 'ls_field' => $field, 00517 'ls_value' => $value, 00518 'ls_log_id' => $logid 00519 ); 00520 } 00521 00522 $dbw = wfGetDB( DB_MASTER ); 00523 $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' ); 00524 00525 return true; 00526 } 00527 00534 public static function makeParamBlob( $params ) { 00535 return implode( "\n", $params ); 00536 } 00537 00544 public static function extractParams( $blob ) { 00545 if ( $blob === '' ) { 00546 return array(); 00547 } else { 00548 return explode( "\n", $blob ); 00549 } 00550 } 00551 00560 public static function formatBlockFlags( $flags, $lang ) { 00561 $flags = trim( $flags ); 00562 if ( $flags === '' ) { 00563 return ''; //nothing to do 00564 } 00565 $flags = explode( ',', $flags ); 00566 $flagsCount = count( $flags ); 00567 00568 for ( $i = 0; $i < $flagsCount; $i++ ) { 00569 $flags[$i] = self::formatBlockFlag( $flags[$i], $lang ); 00570 } 00571 00572 return wfMessage( 'parentheses' )->inLanguage( $lang ) 00573 ->rawParams( $lang->commaList( $flags ) )->escaped(); 00574 } 00575 00583 public static function formatBlockFlag( $flag, $lang ) { 00584 static $messages = array(); 00585 00586 if ( !isset( $messages[$flag] ) ) { 00587 $messages[$flag] = htmlspecialchars( $flag ); // Fallback 00588 00589 // For grepping. The following core messages can be used here: 00590 // * block-log-flags-angry-autoblock 00591 // * block-log-flags-anononly 00592 // * block-log-flags-hiddenname 00593 // * block-log-flags-noautoblock 00594 // * block-log-flags-nocreate 00595 // * block-log-flags-noemail 00596 // * block-log-flags-nousertalk 00597 $msg = wfMessage( 'block-log-flags-' . $flag )->inLanguage( $lang ); 00598 00599 if ( $msg->exists() ) { 00600 $messages[$flag] = $msg->escaped(); 00601 } 00602 } 00603 00604 return $messages[$flag]; 00605 } 00606 00612 public function getName() { 00613 global $wgLogNames; 00614 00615 // BC 00616 if ( isset( $wgLogNames[$this->type] ) ) { 00617 $key = $wgLogNames[$this->type]; 00618 } else { 00619 $key = 'log-name-' . $this->type; 00620 } 00621 00622 return wfMessage( $key ); 00623 } 00624 00630 public function getDescription() { 00631 global $wgLogHeaders; 00632 // BC 00633 if ( isset( $wgLogHeaders[$this->type] ) ) { 00634 $key = $wgLogHeaders[$this->type]; 00635 } else { 00636 $key = 'log-description-' . $this->type; 00637 } 00638 00639 return wfMessage( $key ); 00640 } 00641 00647 public function getRestriction() { 00648 global $wgLogRestrictions; 00649 if ( isset( $wgLogRestrictions[$this->type] ) ) { 00650 $restriction = $wgLogRestrictions[$this->type]; 00651 } else { 00652 // '' always returns true with $user->isAllowed() 00653 $restriction = ''; 00654 } 00655 00656 return $restriction; 00657 } 00658 00664 public function isRestricted() { 00665 $restriction = $this->getRestriction(); 00666 00667 return $restriction !== '' && $restriction !== '*'; 00668 } 00669 }