MediaWiki  REL1_19
LogPage.php
Go to the documentation of this file.
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         /* @acess 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
00104                         );
00105                 } elseif( $this->sendToUDP ) {
00106                         # Don't send private logs to UDP
00107                         if( isset( $wgLogRestrictions[$this->type] ) && $wgLogRestrictions[$this->type] != '*' ) {
00108                                 return true;
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
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 .= wfMsgForContent( 'colon-separator' ) . $this->comment;
00137                         }
00138                 }
00139 
00140                 return $rcComment;
00141         }
00142 
00146         public function getComment() {
00147                 return $this->comment;
00148         }
00149 
00155         public static function validTypes() {
00156                 global $wgLogTypes;
00157                 return $wgLogTypes;
00158         }
00159 
00166         public static function isLogType( $type ) {
00167                 return in_array( $type, LogPage::validTypes() );
00168         }
00169 
00177         public static function logName( $type ) {
00178                 wfDeprecated( __METHOD__, '1.19' );
00179                 global $wgLogNames;
00180 
00181                 if( isset( $wgLogNames[$type] ) ) {
00182                         return str_replace( '_', ' ', wfMsg( $wgLogNames[$type] ) );
00183                 } else {
00184                         // Bogus log types? Perhaps an extension was removed.
00185                         return $type;
00186                 }
00187         }
00188 
00197         public static function logHeader( $type ) {
00198                 wfDeprecated( __METHOD__, '1.19' );
00199                 global $wgLogHeaders;
00200                 return wfMsgExt( $wgLogHeaders[$type], array( 'parseinline' ) );
00201         }
00202 
00216         public static function actionText( $type, $action, $title = null, $skin = null,
00217                 $params = array(), $filterWikilinks = false )
00218         {
00219                 global $wgLang, $wgContLang, $wgLogActions;
00220 
00221                 if ( is_null( $skin ) ) {
00222                         $langObj = $wgContLang;
00223                         $langObjOrNull = null;
00224                 } else {
00225                         $langObj = $wgLang;
00226                         $langObjOrNull = $wgLang;
00227                 }
00228 
00229                 $key = "$type/$action";
00230 
00231                 if( isset( $wgLogActions[$key] ) ) {
00232                         if( is_null( $title ) ) {
00233                                 $rv = wfMsgExt( $wgLogActions[$key], array( 'parsemag', 'escape', 'language' => $langObj ) );
00234                         } else {
00235                                 $titleLink = self::getTitleLink( $type, $langObjOrNull, $title, $params );
00236 
00237                                 if( preg_match( '/^rights\/(rights|autopromote)/', $key ) ) {
00238                                         $rightsnone = wfMsgExt( 'rightsnone', array( 'parsemag', 'language' => $langObj ) );
00239 
00240                                         if( $skin ) {
00241                                                 foreach ( $params as &$param ) {
00242                                                         $groupArray = array_map( 'trim', explode( ',', $param ) );
00243                                                         $groupArray = array_map( array( 'User', 'getGroupMember' ), $groupArray );
00244                                                         $param = $wgLang->listToText( $groupArray );
00245                                                 }
00246                                         }
00247 
00248                                         if( !isset( $params[0] ) || trim( $params[0] ) == '' ) {
00249                                                 $params[0] = $rightsnone;
00250                                         }
00251 
00252                                         if( !isset( $params[1] ) || trim( $params[1] ) == '' ) {
00253                                                 $params[1] = $rightsnone;
00254                                         }
00255                                 }
00256 
00257                                 if( count( $params ) == 0 ) {
00258                                         $rv = wfMsgExt( $wgLogActions[$key], array( 'parsemag', 'escape', 'replaceafter', 'language' => $langObj ), $titleLink );
00259                                 } else {
00260                                         $details = '';
00261                                         array_unshift( $params, $titleLink );
00262 
00263                                         // User suppression
00264                                         if ( preg_match( '/^(block|suppress)\/(block|reblock)$/', $key ) ) {
00265                                                 if ( $skin ) {
00266                                                         $params[1] = '<span class="blockExpiry" dir="ltr" title="' . htmlspecialchars( $params[1] ). '">' .
00267                                                                 $wgLang->translateBlockExpiry( $params[1] ) . '</span>';
00268                                                 } else {
00269                                                         $params[1] = $wgContLang->translateBlockExpiry( $params[1] );
00270                                                 }
00271 
00272                                                 $params[2] = isset( $params[2] ) ?
00273                                                         self::formatBlockFlags( $params[2], $langObj ) : '';
00274                                         // Page protections
00275                                         } elseif ( $type == 'protect' && count($params) == 3 ) {
00276                                                 // Restrictions and expiries
00277                                                 if( $skin ) {
00278                                                         $details .= $wgLang->getDirMark() . htmlspecialchars( " {$params[1]}" );
00279                                                 } else {
00280                                                         $details .= " {$params[1]}";
00281                                                 }
00282 
00283                                                 // Cascading flag...
00284                                                 if( $params[2] ) {
00285                                                         $details .= ' [' . wfMsgExt( 'protect-summary-cascade', array( 'parsemag', 'language' => $langObj ) ) . ']';
00286                                                 }
00287                                         }
00288 
00289                                         $rv = wfMsgExt( $wgLogActions[$key], array( 'parsemag', 'escape', 'replaceafter', 'language' => $langObj ), $params ) . $details;
00290                                 }
00291                         }
00292                 } else {
00293                         global $wgLogActionsHandlers;
00294 
00295                         if( isset( $wgLogActionsHandlers[$key] ) ) {
00296                                 $args = func_get_args();
00297                                 $rv = call_user_func_array( $wgLogActionsHandlers[$key], $args );
00298                         } else {
00299                                 wfDebug( "LogPage::actionText - unknown action $key\n" );
00300                                 $rv = "$action";
00301                         }
00302                 }
00303 
00304                 // For the perplexed, this feature was added in r7855 by Erik.
00305                 // The feature was added because we liked adding [[$1]] in our log entries
00306                 // but the log entries are parsed as Wikitext on RecentChanges but as HTML
00307                 // on Special:Log. The hack is essentially that [[$1]] represented a link
00308                 // to the title in question. The first parameter to the HTML version (Special:Log)
00309                 // is that link in HTML form, and so this just gets rid of the ugly [[]].
00310                 // However, this is a horrible hack and it doesn't work like you expect if, say,
00311                 // you want to link to something OTHER than the title of the log entry.
00312                 // The real problem, which Erik was trying to fix (and it sort-of works now) is
00313                 // that the same messages are being treated as both wikitext *and* HTML.
00314                 if( $filterWikilinks ) {
00315                         $rv = str_replace( '[[', '', $rv );
00316                         $rv = str_replace( ']]', '', $rv );
00317                 }
00318 
00319                 return $rv;
00320         }
00321 
00330         protected static function getTitleLink( $type, $lang, $title, &$params ) {
00331                 global $wgContLang, $wgUserrightsInterwikiDelimiter;
00332 
00333                 if( !$lang ) {
00334                         return $title->getPrefixedText();
00335                 }
00336 
00337                 switch( $type ) {
00338                         case 'move':
00339                                 $titleLink = Linker::link(
00340                                         $title,
00341                                         htmlspecialchars( $title->getPrefixedText() ),
00342                                         array(),
00343                                         array( 'redirect' => 'no' )
00344                                 );
00345 
00346                                 $targetTitle = Title::newFromText( $params[0] );
00347 
00348                                 if ( !$targetTitle ) {
00349                                         # Workaround for broken database
00350                                         $params[0] = htmlspecialchars( $params[0] );
00351                                 } else {
00352                                         $params[0] = Linker::link(
00353                                                 $targetTitle,
00354                                                 htmlspecialchars( $params[0] )
00355                                         );
00356                                 }
00357                                 break;
00358                         case 'block':
00359                                 if( substr( $title->getText(), 0, 1 ) == '#' ) {
00360                                         $titleLink = $title->getText();
00361                                 } else {
00362                                         // @todo Store the user identifier in the parameters
00363                                         // to make this faster for future log entries
00364                                         $id = User::idFromName( $title->getText() );
00365                                         $titleLink = Linker::userLink( $id, $title->getText() )
00366                                                 . Linker::userToolLinks( $id, $title->getText(), false, Linker::TOOL_LINKS_NOBLOCK );
00367                                 }
00368                                 break;
00369                         case 'rights':
00370                                 $text = $wgContLang->ucfirst( $title->getText() );
00371                                 $parts = explode( $wgUserrightsInterwikiDelimiter, $text, 2 );
00372 
00373                                 if ( count( $parts ) == 2 ) {
00374                                         $titleLink = WikiMap::foreignUserLink( $parts[1], $parts[0],
00375                                                 htmlspecialchars( $title->getPrefixedText() ) );
00376 
00377                                         if ( $titleLink !== false ) {
00378                                                 break;
00379                                         }
00380                                 }
00381                                 $titleLink = Linker::link( Title::makeTitle( NS_USER, $text ) );
00382                                 break;
00383                         case 'merge':
00384                                 $titleLink = Linker::link(
00385                                         $title,
00386                                         $title->getPrefixedText(),
00387                                         array(),
00388                                         array( 'redirect' => 'no' )
00389                                 );
00390                                 $params[0] = Linker::link(
00391                                         Title::newFromText( $params[0] ),
00392                                         htmlspecialchars( $params[0] )
00393                                 );
00394                                 $params[1] = $lang->timeanddate( $params[1] );
00395                                 break;
00396                         default:
00397                                 if( $title->isSpecialPage() ) {
00398                                         list( $name, $par ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
00399 
00400                                         # Use the language name for log titles, rather than Log/X
00401                                         if( $name == 'Log' ) {
00402                                                 $titleLink = '(' . Linker::link( $title, LogPage::logName( $par ) ) . ')';
00403                                         } else {
00404                                                 $titleLink = Linker::link( $title );
00405                                         }
00406                                 } else {
00407                                         $titleLink = Linker::link( $title );
00408                                 }
00409                 }
00410 
00411                 return $titleLink;
00412         }
00413 
00426         public function addEntry( $action, $target, $comment, $params = array(), $doer = null ) {
00427                 global $wgContLang;
00428 
00429                 if ( !is_array( $params ) ) {
00430                         $params = array( $params );
00431                 }
00432 
00433                 if ( $comment === null ) {
00434                         $comment = '';
00435                 }
00436 
00437                 # Truncate for whole multibyte characters.
00438                 $comment = $wgContLang->truncate( $comment, 255 );
00439 
00440                 $this->action = $action;
00441                 $this->target = $target;
00442                 $this->comment = $comment;
00443                 $this->params = LogPage::makeParamBlob( $params );
00444 
00445                 if ( $doer === null ) {
00446                         global $wgUser;
00447                         $doer = $wgUser;
00448                 } elseif ( !is_object( $doer ) ) {
00449                         $doer = User::newFromId( $doer );
00450                 }
00451 
00452                 $this->doer = $doer;
00453 
00454                 $logEntry = new ManualLogEntry( $this->type, $action );
00455                 $logEntry->setTarget( $target );
00456                 $logEntry->setPerformer( $doer );
00457                 $logEntry->setParameters( $params );
00458 
00459                 $formatter = LogFormatter::newFromEntry( $logEntry );
00460                 $context = RequestContext::newExtraneousContext( $target );
00461                 $formatter->setContext( $context );
00462 
00463                 $this->actionText = $formatter->getPlainActionText();
00464 
00465                 return $this->saveContent();
00466         }
00467 
00476         public function addRelations( $field, $values, $logid ) {
00477                 if( !strlen( $field ) || empty( $values ) ) {
00478                         return false; // nothing
00479                 }
00480 
00481                 $data = array();
00482 
00483                 foreach( $values as $value ) {
00484                         $data[] = array(
00485                                 'ls_field' => $field,
00486                                 'ls_value' => $value,
00487                                 'ls_log_id' => $logid
00488                         );
00489                 }
00490 
00491                 $dbw = wfGetDB( DB_MASTER );
00492                 $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' );
00493 
00494                 return true;
00495         }
00496 
00503         public static function makeParamBlob( $params ) {
00504                 return implode( "\n", $params );
00505         }
00506 
00513         public static function extractParams( $blob ) {
00514                 if ( $blob === '' ) {
00515                         return array();
00516                 } else {
00517                         return explode( "\n", $blob );
00518                 }
00519         }
00520 
00529         public static function formatBlockFlags( $flags, $lang ) {
00530                 $flags = explode( ',', trim( $flags ) );
00531 
00532                 if( count( $flags ) > 0 ) {
00533                         for( $i = 0; $i < count( $flags ); $i++ ) {
00534                                 $flags[$i] = self::formatBlockFlag( $flags[$i], $lang );
00535                         }
00536                         return '(' . $lang->commaList( $flags ) . ')';
00537                 } else {
00538                         return '';
00539                 }
00540         }
00541 
00549         public static function formatBlockFlag( $flag, $lang ) {
00550                 static $messages = array();
00551 
00552                 if( !isset( $messages[$flag] ) ) {
00553                         $messages[$flag] = htmlspecialchars( $flag ); // Fallback
00554 
00555                         // For grepping. The following core messages can be used here:
00556                         // * block-log-flags-angry-autoblock
00557                         // * block-log-flags-anononly
00558                         // * block-log-flags-hiddenname
00559                         // * block-log-flags-noautoblock
00560                         // * block-log-flags-nocreate
00561                         // * block-log-flags-noemail
00562                         // * block-log-flags-nousertalk
00563                         $msg = wfMessage( 'block-log-flags-' . $flag )->inLanguage( $lang );
00564 
00565                         if ( $msg->exists() ) {
00566                                 $messages[$flag] = $msg->escaped();
00567                         }
00568                 }
00569 
00570                 return $messages[$flag];
00571         }
00572 
00573 
00579         public function getName() {
00580                 global $wgLogNames;
00581 
00582                 // BC
00583                 if ( isset( $wgLogNames[$this->type] ) ) {
00584                         $key = $wgLogNames[$this->type];
00585                 } else {
00586                         $key = 'log-name-' . $this->type;
00587                 }
00588 
00589                 return wfMessage( $key );
00590         }
00591 
00597         public function getDescription() {
00598                 global $wgLogHeaders;
00599                 // BC
00600                 if ( isset( $wgLogHeaders[$this->type] ) ) {
00601                         $key = $wgLogHeaders[$this->type];
00602                 } else {
00603                         $key = 'log-description-' . $this->type;
00604                 }
00605                 return wfMessage( $key );
00606         }
00607 
00613         public function getRestriction() {
00614                 global $wgLogRestrictions;
00615                 if ( isset( $wgLogRestrictions[$this->type] ) ) {
00616                         $restriction = $wgLogRestrictions[$this->type];
00617                 } else {
00618                         // '' always returns true with $user->isAllowed()
00619                         $restriction = '';
00620                 }
00621                 return $restriction;
00622         }
00623 
00629         public function isRestricted() {
00630                 $restriction = $this->getRestriction();
00631                 return $restriction !== '' && $restriction !== '*';
00632         }
00633 
00634 }