MediaWiki
REL1_22
|
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 // Convenience fields 00038 const SUPPRESSED_USER = 12; 00039 const SUPPRESSED_ACTION = 9; 00040 /* @access private */ 00041 var $type, $action, $comment, $params; 00042 00046 var $doer; 00047 00051 var $target; 00052 00053 /* @access public */ 00054 var $updateRecentChanges, $sendToUDP; 00055 00064 public function __construct( $type, $rc = true, $udp = 'skipUDP' ) { 00065 $this->type = $type; 00066 $this->updateRecentChanges = $rc; 00067 $this->sendToUDP = ( $udp == 'UDP' ); 00068 } 00069 00073 protected function saveContent() { 00074 global $wgLogRestrictions; 00075 00076 $dbw = wfGetDB( DB_MASTER ); 00077 $log_id = $dbw->nextSequenceValue( 'logging_log_id_seq' ); 00078 00079 $this->timestamp = $now = wfTimestampNow(); 00080 $data = array( 00081 'log_id' => $log_id, 00082 'log_type' => $this->type, 00083 'log_action' => $this->action, 00084 'log_timestamp' => $dbw->timestamp( $now ), 00085 'log_user' => $this->doer->getId(), 00086 'log_user_text' => $this->doer->getName(), 00087 'log_namespace' => $this->target->getNamespace(), 00088 'log_title' => $this->target->getDBkey(), 00089 'log_page' => $this->target->getArticleID(), 00090 'log_comment' => $this->comment, 00091 'log_params' => $this->params 00092 ); 00093 $dbw->insert( 'logging', $data, __METHOD__ ); 00094 $newId = !is_null( $log_id ) ? $log_id : $dbw->insertId(); 00095 00096 # And update recentchanges 00097 if ( $this->updateRecentChanges ) { 00098 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); 00099 00100 RecentChange::notifyLog( 00101 $now, $titleObj, $this->doer, $this->getRcComment(), '', 00102 $this->type, $this->action, $this->target, $this->comment, 00103 $this->params, $newId, $this->getRcCommentIRC() 00104 ); 00105 } elseif ( $this->sendToUDP ) { 00106 # Don't send private logs to UDP 00107 if ( isset( $wgLogRestrictions[$this->type] ) && $wgLogRestrictions[$this->type] != '*' ) { 00108 return $newId; 00109 } 00110 00111 # Notify external application via UDP. 00112 # We send this to IRC but do not want to add it the RC table. 00113 $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); 00114 $rc = RecentChange::newLogEntry( 00115 $now, $titleObj, $this->doer, $this->getRcComment(), '', 00116 $this->type, $this->action, $this->target, $this->comment, 00117 $this->params, $newId, $this->getRcCommentIRC() 00118 ); 00119 $rc->notifyRC2UDP(); 00120 } 00121 return $newId; 00122 } 00123 00129 public function getRcComment() { 00130 $rcComment = $this->actionText; 00131 00132 if ( $this->comment != '' ) { 00133 if ( $rcComment == '' ) { 00134 $rcComment = $this->comment; 00135 } else { 00136 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . 00137 $this->comment; 00138 } 00139 } 00140 00141 return $rcComment; 00142 } 00143 00149 public function getRcCommentIRC() { 00150 $rcComment = $this->ircActionText; 00151 00152 if ( $this->comment != '' ) { 00153 if ( $rcComment == '' ) { 00154 $rcComment = $this->comment; 00155 } else { 00156 $rcComment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . 00157 $this->comment; 00158 } 00159 } 00160 00161 return $rcComment; 00162 } 00163 00167 public function getComment() { 00168 return $this->comment; 00169 } 00170 00176 public static function validTypes() { 00177 global $wgLogTypes; 00178 return $wgLogTypes; 00179 } 00180 00187 public static function isLogType( $type ) { 00188 return in_array( $type, LogPage::validTypes() ); 00189 } 00190 00198 public static function logName( $type ) { 00199 global $wgLogNames; 00200 00201 if ( isset( $wgLogNames[$type] ) ) { 00202 return str_replace( '_', ' ', wfMessage( $wgLogNames[$type] )->text() ); 00203 } else { 00204 // Bogus log types? Perhaps an extension was removed. 00205 return $type; 00206 } 00207 } 00208 00217 public static function logHeader( $type ) { 00218 global $wgLogHeaders; 00219 return wfMessage( $wgLogHeaders[$type] )->parse(); 00220 } 00221 00235 public static function actionText( $type, $action, $title = null, $skin = null, 00236 $params = array(), $filterWikilinks = false ) 00237 { 00238 global $wgLang, $wgContLang, $wgLogActions; 00239 00240 if ( is_null( $skin ) ) { 00241 $langObj = $wgContLang; 00242 $langObjOrNull = null; 00243 } else { 00244 $langObj = $wgLang; 00245 $langObjOrNull = $wgLang; 00246 } 00247 00248 $key = "$type/$action"; 00249 00250 if ( isset( $wgLogActions[$key] ) ) { 00251 if ( is_null( $title ) ) { 00252 $rv = wfMessage( $wgLogActions[$key] )->inLanguage( $langObj )->escaped(); 00253 } else { 00254 $titleLink = self::getTitleLink( $type, $langObjOrNull, $title, $params ); 00255 00256 if ( count( $params ) == 0 ) { 00257 $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink )->inLanguage( $langObj )->escaped(); 00258 } else { 00259 $details = ''; 00260 array_unshift( $params, $titleLink ); 00261 00262 // User suppression 00263 if ( preg_match( '/^(block|suppress)\/(block|reblock)$/', $key ) ) { 00264 if ( $skin ) { 00265 $params[1] = '<span class="blockExpiry" title="‎' . htmlspecialchars( $params[1] ) . '">' . 00266 $wgLang->translateBlockExpiry( $params[1] ) . '</span>'; 00267 } else { 00268 $params[1] = $wgContLang->translateBlockExpiry( $params[1] ); 00269 } 00270 00271 $params[2] = isset( $params[2] ) ? 00272 self::formatBlockFlags( $params[2], $langObj ) : ''; 00273 // Page protections 00274 } elseif ( $type == 'protect' && count( $params ) == 3 ) { 00275 // Restrictions and expiries 00276 if ( $skin ) { 00277 $details .= $wgLang->getDirMark() . htmlspecialchars( " {$params[1]}" ); 00278 } else { 00279 $details .= " {$params[1]}"; 00280 } 00281 00282 // Cascading flag... 00283 if ( $params[2] ) { 00284 $details .= ' [' . wfMessage( 'protect-summary-cascade' )->inLanguage( $langObj )->text() . ']'; 00285 } 00286 } 00287 00288 $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params )->inLanguage( $langObj )->escaped() . $details; 00289 } 00290 } 00291 } else { 00292 global $wgLogActionsHandlers; 00293 00294 if ( isset( $wgLogActionsHandlers[$key] ) ) { 00295 $args = func_get_args(); 00296 $rv = call_user_func_array( $wgLogActionsHandlers[$key], $args ); 00297 } else { 00298 wfDebug( "LogPage::actionText - unknown action $key\n" ); 00299 $rv = "$action"; 00300 } 00301 } 00302 00303 // For the perplexed, this feature was added in r7855 by Erik. 00304 // The feature was added because we liked adding [[$1]] in our log entries 00305 // but the log entries are parsed as Wikitext on RecentChanges but as HTML 00306 // on Special:Log. The hack is essentially that [[$1]] represented a link 00307 // to the title in question. The first parameter to the HTML version (Special:Log) 00308 // is that link in HTML form, and so this just gets rid of the ugly [[]]. 00309 // However, this is a horrible hack and it doesn't work like you expect if, say, 00310 // you want to link to something OTHER than the title of the log entry. 00311 // The real problem, which Erik was trying to fix (and it sort-of works now) is 00312 // that the same messages are being treated as both wikitext *and* HTML. 00313 if ( $filterWikilinks ) { 00314 $rv = str_replace( '[[', '', $rv ); 00315 $rv = str_replace( ']]', '', $rv ); 00316 } 00317 00318 return $rv; 00319 } 00320 00329 protected static function getTitleLink( $type, $lang, $title, &$params ) { 00330 if ( !$lang ) { 00331 return $title->getPrefixedText(); 00332 } 00333 00334 switch ( $type ) { 00335 case 'move': 00336 $titleLink = Linker::link( 00337 $title, 00338 htmlspecialchars( $title->getPrefixedText() ), 00339 array(), 00340 array( 'redirect' => 'no' ) 00341 ); 00342 00343 $targetTitle = Title::newFromText( $params[0] ); 00344 00345 if ( !$targetTitle ) { 00346 # Workaround for broken database 00347 $params[0] = htmlspecialchars( $params[0] ); 00348 } else { 00349 $params[0] = Linker::link( 00350 $targetTitle, 00351 htmlspecialchars( $params[0] ) 00352 ); 00353 } 00354 break; 00355 case 'block': 00356 if ( substr( $title->getText(), 0, 1 ) == '#' ) { 00357 $titleLink = $title->getText(); 00358 } else { 00359 // @todo Store the user identifier in the parameters 00360 // to make this faster for future log entries 00361 $id = User::idFromName( $title->getText() ); 00362 $titleLink = Linker::userLink( $id, $title->getText() ) 00363 . Linker::userToolLinks( $id, $title->getText(), false, Linker::TOOL_LINKS_NOBLOCK ); 00364 } 00365 break; 00366 case 'merge': 00367 $titleLink = Linker::link( 00368 $title, 00369 $title->getPrefixedText(), 00370 array(), 00371 array( 'redirect' => 'no' ) 00372 ); 00373 $params[0] = Linker::link( 00374 Title::newFromText( $params[0] ), 00375 htmlspecialchars( $params[0] ) 00376 ); 00377 $params[1] = $lang->timeanddate( $params[1] ); 00378 break; 00379 default: 00380 if ( $title->isSpecialPage() ) { 00381 list( $name, $par ) = SpecialPageFactory::resolveAlias( $title->getDBkey() ); 00382 00383 # Use the language name for log titles, rather than Log/X 00384 if ( $name == 'Log' ) { 00385 $logPage = new LogPage( $par ); 00386 $titleLink = Linker::link( $title, $logPage->getName()->escaped() ); 00387 $titleLink = wfMessage( 'parentheses' ) 00388 ->inLanguage( $lang ) 00389 ->rawParams( $titleLink ) 00390 ->escaped(); 00391 } else { 00392 $titleLink = Linker::link( $title ); 00393 } 00394 } else { 00395 $titleLink = Linker::link( $title ); 00396 } 00397 } 00398 00399 return $titleLink; 00400 } 00401 00413 public function addEntry( $action, $target, $comment, $params = array(), $doer = null ) { 00414 global $wgContLang; 00415 00416 if ( !is_array( $params ) ) { 00417 $params = array( $params ); 00418 } 00419 00420 if ( $comment === null ) { 00421 $comment = ''; 00422 } 00423 00424 # Trim spaces on user supplied text 00425 $comment = trim( $comment ); 00426 00427 # Truncate for whole multibyte characters. 00428 $comment = $wgContLang->truncate( $comment, 255 ); 00429 00430 $this->action = $action; 00431 $this->target = $target; 00432 $this->comment = $comment; 00433 $this->params = LogPage::makeParamBlob( $params ); 00434 00435 if ( $doer === null ) { 00436 global $wgUser; 00437 $doer = $wgUser; 00438 } elseif ( !is_object( $doer ) ) { 00439 $doer = User::newFromId( $doer ); 00440 } 00441 00442 $this->doer = $doer; 00443 00444 $logEntry = new ManualLogEntry( $this->type, $action ); 00445 $logEntry->setTarget( $target ); 00446 $logEntry->setPerformer( $doer ); 00447 $logEntry->setParameters( $params ); 00448 00449 $formatter = LogFormatter::newFromEntry( $logEntry ); 00450 $context = RequestContext::newExtraneousContext( $target ); 00451 $formatter->setContext( $context ); 00452 00453 $this->actionText = $formatter->getPlainActionText(); 00454 $this->ircActionText = $formatter->getIRCActionText(); 00455 00456 return $this->saveContent(); 00457 } 00458 00467 public function addRelations( $field, $values, $logid ) { 00468 if ( !strlen( $field ) || empty( $values ) ) { 00469 return false; // nothing 00470 } 00471 00472 $data = array(); 00473 00474 foreach ( $values as $value ) { 00475 $data[] = array( 00476 'ls_field' => $field, 00477 'ls_value' => $value, 00478 'ls_log_id' => $logid 00479 ); 00480 } 00481 00482 $dbw = wfGetDB( DB_MASTER ); 00483 $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' ); 00484 00485 return true; 00486 } 00487 00494 public static function makeParamBlob( $params ) { 00495 return implode( "\n", $params ); 00496 } 00497 00504 public static function extractParams( $blob ) { 00505 if ( $blob === '' ) { 00506 return array(); 00507 } else { 00508 return explode( "\n", $blob ); 00509 } 00510 } 00511 00520 public static function formatBlockFlags( $flags, $lang ) { 00521 $flags = trim( $flags ); 00522 if ( $flags === '' ) { 00523 return ''; //nothing to do 00524 } 00525 $flags = explode( ',', $flags ); 00526 00527 for ( $i = 0; $i < count( $flags ); $i++ ) { 00528 $flags[$i] = self::formatBlockFlag( $flags[$i], $lang ); 00529 } 00530 return wfMessage( 'parentheses' )->inLanguage( $lang ) 00531 ->rawParams( $lang->commaList( $flags ) )->escaped(); 00532 } 00533 00541 public static function formatBlockFlag( $flag, $lang ) { 00542 static $messages = array(); 00543 00544 if ( !isset( $messages[$flag] ) ) { 00545 $messages[$flag] = htmlspecialchars( $flag ); // Fallback 00546 00547 // For grepping. The following core messages can be used here: 00548 // * block-log-flags-angry-autoblock 00549 // * block-log-flags-anononly 00550 // * block-log-flags-hiddenname 00551 // * block-log-flags-noautoblock 00552 // * block-log-flags-nocreate 00553 // * block-log-flags-noemail 00554 // * block-log-flags-nousertalk 00555 $msg = wfMessage( 'block-log-flags-' . $flag )->inLanguage( $lang ); 00556 00557 if ( $msg->exists() ) { 00558 $messages[$flag] = $msg->escaped(); 00559 } 00560 } 00561 00562 return $messages[$flag]; 00563 } 00564 00570 public function getName() { 00571 global $wgLogNames; 00572 00573 // BC 00574 if ( isset( $wgLogNames[$this->type] ) ) { 00575 $key = $wgLogNames[$this->type]; 00576 } else { 00577 $key = 'log-name-' . $this->type; 00578 } 00579 00580 return wfMessage( $key ); 00581 } 00582 00588 public function getDescription() { 00589 global $wgLogHeaders; 00590 // BC 00591 if ( isset( $wgLogHeaders[$this->type] ) ) { 00592 $key = $wgLogHeaders[$this->type]; 00593 } else { 00594 $key = 'log-description-' . $this->type; 00595 } 00596 return wfMessage( $key ); 00597 } 00598 00604 public function getRestriction() { 00605 global $wgLogRestrictions; 00606 if ( isset( $wgLogRestrictions[$this->type] ) ) { 00607 $restriction = $wgLogRestrictions[$this->type]; 00608 } else { 00609 // '' always returns true with $user->isAllowed() 00610 $restriction = ''; 00611 } 00612 return $restriction; 00613 } 00614 00620 public function isRestricted() { 00621 $restriction = $this->getRestriction(); 00622 return $restriction !== '' && $restriction !== '*'; 00623 } 00624 00625 }