MediaWiki  REL1_21
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         /* @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" dir="ltr" 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 = explode( ',', trim( $flags ) );
00522 
00523                 if( count( $flags ) > 0 ) {
00524                         for( $i = 0; $i < count( $flags ); $i++ ) {
00525                                 $flags[$i] = self::formatBlockFlag( $flags[$i], $lang );
00526                         }
00527                         return wfMessage( 'parentheses' )->inLanguage( $lang )
00528                                 ->rawParams( $lang->commaList( $flags ) )->escaped();
00529                 } else {
00530                         return '';
00531                 }
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 }