MediaWiki  REL1_20
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, $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( preg_match( '/^rights\/(rights|autopromote)/', $key ) ) {
00257                                         $rightsnone = wfMessage( 'rightsnone' )->inLanguage( $langObj )->text();
00258 
00259                                         if( $skin ) {
00260                                                 $username = $title->getText();
00261                                                 foreach ( $params as &$param ) {
00262                                                         $groupArray = array_map( 'trim', explode( ',', $param ) );
00263                                                         foreach( $groupArray as &$group ) {
00264                                                                 $group = User::getGroupMember( $group, $username );
00265                                                         }
00266                                                         $param = $wgLang->listToText( $groupArray );
00267                                                 }
00268                                         }
00269 
00270                                         if( !isset( $params[0] ) || trim( $params[0] ) == '' ) {
00271                                                 $params[0] = $rightsnone;
00272                                         }
00273 
00274                                         if( !isset( $params[1] ) || trim( $params[1] ) == '' ) {
00275                                                 $params[1] = $rightsnone;
00276                                         }
00277                                 }
00278 
00279                                 if( count( $params ) == 0 ) {
00280                                         $rv = wfMessage( $wgLogActions[$key] )->rawParams( $titleLink )->inLanguage( $langObj )->escaped();
00281                                 } else {
00282                                         $details = '';
00283                                         array_unshift( $params, $titleLink );
00284 
00285                                         // User suppression
00286                                         if ( preg_match( '/^(block|suppress)\/(block|reblock)$/', $key ) ) {
00287                                                 if ( $skin ) {
00288                                                         $params[1] = '<span class="blockExpiry" dir="ltr" title="' . htmlspecialchars( $params[1] ). '">' .
00289                                                                 $wgLang->translateBlockExpiry( $params[1] ) . '</span>';
00290                                                 } else {
00291                                                         $params[1] = $wgContLang->translateBlockExpiry( $params[1] );
00292                                                 }
00293 
00294                                                 $params[2] = isset( $params[2] ) ?
00295                                                         self::formatBlockFlags( $params[2], $langObj ) : '';
00296                                         // Page protections
00297                                         } elseif ( $type == 'protect' && count($params) == 3 ) {
00298                                                 // Restrictions and expiries
00299                                                 if( $skin ) {
00300                                                         $details .= $wgLang->getDirMark() . htmlspecialchars( " {$params[1]}" );
00301                                                 } else {
00302                                                         $details .= " {$params[1]}";
00303                                                 }
00304 
00305                                                 // Cascading flag...
00306                                                 if( $params[2] ) {
00307                                                         $details .= ' [' . wfMessage( 'protect-summary-cascade' )->inLanguage( $langObj )->text() . ']';
00308                                                 }
00309                                         }
00310 
00311                                         $rv = wfMessage( $wgLogActions[$key] )->rawParams( $params )->inLanguage( $langObj )->escaped() . $details;
00312                                 }
00313                         }
00314                 } else {
00315                         global $wgLogActionsHandlers;
00316 
00317                         if( isset( $wgLogActionsHandlers[$key] ) ) {
00318                                 $args = func_get_args();
00319                                 $rv = call_user_func_array( $wgLogActionsHandlers[$key], $args );
00320                         } else {
00321                                 wfDebug( "LogPage::actionText - unknown action $key\n" );
00322                                 $rv = "$action";
00323                         }
00324                 }
00325 
00326                 // For the perplexed, this feature was added in r7855 by Erik.
00327                 // The feature was added because we liked adding [[$1]] in our log entries
00328                 // but the log entries are parsed as Wikitext on RecentChanges but as HTML
00329                 // on Special:Log. The hack is essentially that [[$1]] represented a link
00330                 // to the title in question. The first parameter to the HTML version (Special:Log)
00331                 // is that link in HTML form, and so this just gets rid of the ugly [[]].
00332                 // However, this is a horrible hack and it doesn't work like you expect if, say,
00333                 // you want to link to something OTHER than the title of the log entry.
00334                 // The real problem, which Erik was trying to fix (and it sort-of works now) is
00335                 // that the same messages are being treated as both wikitext *and* HTML.
00336                 if( $filterWikilinks ) {
00337                         $rv = str_replace( '[[', '', $rv );
00338                         $rv = str_replace( ']]', '', $rv );
00339                 }
00340 
00341                 return $rv;
00342         }
00343 
00352         protected static function getTitleLink( $type, $lang, $title, &$params ) {
00353                 global $wgContLang, $wgUserrightsInterwikiDelimiter;
00354 
00355                 if( !$lang ) {
00356                         return $title->getPrefixedText();
00357                 }
00358 
00359                 switch( $type ) {
00360                         case 'move':
00361                                 $titleLink = Linker::link(
00362                                         $title,
00363                                         htmlspecialchars( $title->getPrefixedText() ),
00364                                         array(),
00365                                         array( 'redirect' => 'no' )
00366                                 );
00367 
00368                                 $targetTitle = Title::newFromText( $params[0] );
00369 
00370                                 if ( !$targetTitle ) {
00371                                         # Workaround for broken database
00372                                         $params[0] = htmlspecialchars( $params[0] );
00373                                 } else {
00374                                         $params[0] = Linker::link(
00375                                                 $targetTitle,
00376                                                 htmlspecialchars( $params[0] )
00377                                         );
00378                                 }
00379                                 break;
00380                         case 'block':
00381                                 if( substr( $title->getText(), 0, 1 ) == '#' ) {
00382                                         $titleLink = $title->getText();
00383                                 } else {
00384                                         // @todo Store the user identifier in the parameters
00385                                         // to make this faster for future log entries
00386                                         $id = User::idFromName( $title->getText() );
00387                                         $titleLink = Linker::userLink( $id, $title->getText() )
00388                                                 . Linker::userToolLinks( $id, $title->getText(), false, Linker::TOOL_LINKS_NOBLOCK );
00389                                 }
00390                                 break;
00391                         case 'rights':
00392                                 $text = $wgContLang->ucfirst( $title->getText() );
00393                                 $parts = explode( $wgUserrightsInterwikiDelimiter, $text, 2 );
00394 
00395                                 if ( count( $parts ) == 2 ) {
00396                                         $titleLink = WikiMap::foreignUserLink( $parts[1], $parts[0],
00397                                                 htmlspecialchars( $title->getPrefixedText() ) );
00398 
00399                                         if ( $titleLink !== false ) {
00400                                                 break;
00401                                         }
00402                                 }
00403                                 $titleLink = Linker::link( Title::makeTitle( NS_USER, $text ) );
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 
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                 # Truncate for whole multibyte characters.
00464                 $comment = $wgContLang->truncate( $comment, 255 );
00465 
00466                 $this->action = $action;
00467                 $this->target = $target;
00468                 $this->comment = $comment;
00469                 $this->params = LogPage::makeParamBlob( $params );
00470 
00471                 if ( $doer === null ) {
00472                         global $wgUser;
00473                         $doer = $wgUser;
00474                 } elseif ( !is_object( $doer ) ) {
00475                         $doer = User::newFromId( $doer );
00476                 }
00477 
00478                 $this->doer = $doer;
00479 
00480                 $logEntry = new ManualLogEntry( $this->type, $action );
00481                 $logEntry->setTarget( $target );
00482                 $logEntry->setPerformer( $doer );
00483                 $logEntry->setParameters( $params );
00484 
00485                 $formatter = LogFormatter::newFromEntry( $logEntry );
00486                 $context = RequestContext::newExtraneousContext( $target );
00487                 $formatter->setContext( $context );
00488 
00489                 $this->actionText = $formatter->getPlainActionText();
00490                 $this->ircActionText = $formatter->getIRCActionText();
00491 
00492                 return $this->saveContent();
00493         }
00494 
00503         public function addRelations( $field, $values, $logid ) {
00504                 if( !strlen( $field ) || empty( $values ) ) {
00505                         return false; // nothing
00506                 }
00507 
00508                 $data = array();
00509 
00510                 foreach( $values as $value ) {
00511                         $data[] = array(
00512                                 'ls_field' => $field,
00513                                 'ls_value' => $value,
00514                                 'ls_log_id' => $logid
00515                         );
00516                 }
00517 
00518                 $dbw = wfGetDB( DB_MASTER );
00519                 $dbw->insert( 'log_search', $data, __METHOD__, 'IGNORE' );
00520 
00521                 return true;
00522         }
00523 
00530         public static function makeParamBlob( $params ) {
00531                 return implode( "\n", $params );
00532         }
00533 
00540         public static function extractParams( $blob ) {
00541                 if ( $blob === '' ) {
00542                         return array();
00543                 } else {
00544                         return explode( "\n", $blob );
00545                 }
00546         }
00547 
00556         public static function formatBlockFlags( $flags, $lang ) {
00557                 $flags = explode( ',', trim( $flags ) );
00558 
00559                 if( count( $flags ) > 0 ) {
00560                         for( $i = 0; $i < count( $flags ); $i++ ) {
00561                                 $flags[$i] = self::formatBlockFlag( $flags[$i], $lang );
00562                         }
00563                         return wfMessage( 'parentheses' )->inLanguage( $lang )
00564                                 ->rawParams( $lang->commaList( $flags ) )->escaped();
00565                 } else {
00566                         return '';
00567                 }
00568         }
00569 
00577         public static function formatBlockFlag( $flag, $lang ) {
00578                 static $messages = array();
00579 
00580                 if( !isset( $messages[$flag] ) ) {
00581                         $messages[$flag] = htmlspecialchars( $flag ); // Fallback
00582 
00583                         // For grepping. The following core messages can be used here:
00584                         // * block-log-flags-angry-autoblock
00585                         // * block-log-flags-anononly
00586                         // * block-log-flags-hiddenname
00587                         // * block-log-flags-noautoblock
00588                         // * block-log-flags-nocreate
00589                         // * block-log-flags-noemail
00590                         // * block-log-flags-nousertalk
00591                         $msg = wfMessage( 'block-log-flags-' . $flag )->inLanguage( $lang );
00592 
00593                         if ( $msg->exists() ) {
00594                                 $messages[$flag] = $msg->escaped();
00595                         }
00596                 }
00597 
00598                 return $messages[$flag];
00599         }
00600 
00601 
00607         public function getName() {
00608                 global $wgLogNames;
00609 
00610                 // BC
00611                 if ( isset( $wgLogNames[$this->type] ) ) {
00612                         $key = $wgLogNames[$this->type];
00613                 } else {
00614                         $key = 'log-name-' . $this->type;
00615                 }
00616 
00617                 return wfMessage( $key );
00618         }
00619 
00625         public function getDescription() {
00626                 global $wgLogHeaders;
00627                 // BC
00628                 if ( isset( $wgLogHeaders[$this->type] ) ) {
00629                         $key = $wgLogHeaders[$this->type];
00630                 } else {
00631                         $key = 'log-description-' . $this->type;
00632                 }
00633                 return wfMessage( $key );
00634         }
00635 
00641         public function getRestriction() {
00642                 global $wgLogRestrictions;
00643                 if ( isset( $wgLogRestrictions[$this->type] ) ) {
00644                         $restriction = $wgLogRestrictions[$this->type];
00645                 } else {
00646                         // '' always returns true with $user->isAllowed()
00647                         $restriction = '';
00648                 }
00649                 return $restriction;
00650         }
00651 
00657         public function isRestricted() {
00658                 $restriction = $this->getRestriction();
00659                 return $restriction !== '' && $restriction !== '*';
00660         }
00661 
00662 }