MediaWiki REL1_28
RecentChange.php
Go to the documentation of this file.
1<?php
64 // Constants for the rc_source field. Extensions may also have
65 // their own source constants.
66 const SRC_EDIT = 'mw.edit';
67 const SRC_NEW = 'mw.new';
68 const SRC_LOG = 'mw.log';
69 const SRC_EXTERNAL = 'mw.external'; // obsolete
70 const SRC_CATEGORIZE = 'mw.categorize';
71
72 public $mAttribs = [];
73 public $mExtra = [];
74
78 public $mTitle = false;
79
83 private $mPerformer = false;
84
85 public $numberofWatchingusers = 0; # Dummy to prevent error message in SpecialRecentChangesLinked
87
91 public $counter = -1;
92
96 private $tags = [];
97
101 private static $changeTypes = [
102 'edit' => RC_EDIT,
103 'new' => RC_NEW,
104 'log' => RC_LOG,
105 'external' => RC_EXTERNAL,
106 'categorize' => RC_CATEGORIZE,
107 ];
108
109 # Factory methods
110
115 public static function newFromRow( $row ) {
116 $rc = new RecentChange;
117 $rc->loadFromRow( $row );
118
119 return $rc;
120 }
121
129 public static function parseToRCType( $type ) {
130 if ( is_array( $type ) ) {
131 $retval = [];
132 foreach ( $type as $t ) {
134 }
135
136 return $retval;
137 }
138
139 if ( !array_key_exists( $type, self::$changeTypes ) ) {
140 throw new MWException( "Unknown type '$type'" );
141 }
142 return self::$changeTypes[$type];
143 }
144
151 public static function parseFromRCType( $rcType ) {
152 return array_search( $rcType, self::$changeTypes, true ) ?: "$rcType";
153 }
154
162 public static function getChangeTypes() {
163 return array_keys( self::$changeTypes );
164 }
165
172 public static function newFromId( $rcid ) {
173 return self::newFromConds( [ 'rc_id' => $rcid ], __METHOD__ );
174 }
175
185 public static function newFromConds(
186 $conds,
187 $fname = __METHOD__,
188 $dbType = DB_REPLICA
189 ) {
190 $db = wfGetDB( $dbType );
191 $row = $db->selectRow( 'recentchanges', self::selectFields(), $conds, $fname );
192 if ( $row !== false ) {
193 return self::newFromRow( $row );
194 } else {
195 return null;
196 }
197 }
198
204 public static function selectFields() {
205 return [
206 'rc_id',
207 'rc_timestamp',
208 'rc_user',
209 'rc_user_text',
210 'rc_namespace',
211 'rc_title',
212 'rc_comment',
213 'rc_minor',
214 'rc_bot',
215 'rc_new',
216 'rc_cur_id',
217 'rc_this_oldid',
218 'rc_last_oldid',
219 'rc_type',
220 'rc_source',
221 'rc_patrolled',
222 'rc_ip',
223 'rc_old_len',
224 'rc_new_len',
225 'rc_deleted',
226 'rc_logid',
227 'rc_log_type',
228 'rc_log_action',
229 'rc_params',
230 ];
231 }
232
233 # Accessors
234
238 public function setAttribs( $attribs ) {
239 $this->mAttribs = $attribs;
240 }
241
245 public function setExtra( $extra ) {
246 $this->mExtra = $extra;
247 }
248
252 public function &getTitle() {
253 if ( $this->mTitle === false ) {
254 $this->mTitle = Title::makeTitle( $this->mAttribs['rc_namespace'], $this->mAttribs['rc_title'] );
255 }
256
257 return $this->mTitle;
258 }
259
265 public function getPerformer() {
266 if ( $this->mPerformer === false ) {
267 if ( $this->mAttribs['rc_user'] ) {
268 $this->mPerformer = User::newFromId( $this->mAttribs['rc_user'] );
269 } else {
270 $this->mPerformer = User::newFromName( $this->mAttribs['rc_user_text'], false );
271 }
272 }
273
274 return $this->mPerformer;
275 }
276
281 public function save( $noudp = false ) {
283
284 $dbw = wfGetDB( DB_MASTER );
285 if ( !is_array( $this->mExtra ) ) {
286 $this->mExtra = [];
287 }
288
289 if ( !$wgPutIPinRC ) {
290 $this->mAttribs['rc_ip'] = '';
291 }
292
293 # Strict mode fixups (not-NULL fields)
294 foreach ( [ 'minor', 'bot', 'new', 'patrolled', 'deleted' ] as $field ) {
295 $this->mAttribs["rc_$field"] = (int)$this->mAttribs["rc_$field"];
296 }
297 # ...more fixups (NULL fields)
298 foreach ( [ 'old_len', 'new_len' ] as $field ) {
299 $this->mAttribs["rc_$field"] = isset( $this->mAttribs["rc_$field"] )
300 ? (int)$this->mAttribs["rc_$field"]
301 : null;
302 }
303
304 # If our database is strict about IP addresses, use NULL instead of an empty string
305 $strictIPs = in_array( $dbw->getType(), [ 'oracle', 'postgres' ] ); // legacy
306 if ( $strictIPs && $this->mAttribs['rc_ip'] == '' ) {
307 unset( $this->mAttribs['rc_ip'] );
308 }
309
310 # Trim spaces on user supplied text
311 $this->mAttribs['rc_comment'] = trim( $this->mAttribs['rc_comment'] );
312
313 # Make sure summary is truncated (whole multibyte characters)
314 $this->mAttribs['rc_comment'] = $wgContLang->truncate( $this->mAttribs['rc_comment'], 255 );
315
316 # Fixup database timestamps
317 $this->mAttribs['rc_timestamp'] = $dbw->timestamp( $this->mAttribs['rc_timestamp'] );
318 $this->mAttribs['rc_id'] = $dbw->nextSequenceValue( 'recentchanges_rc_id_seq' );
319
320 # # If we are using foreign keys, an entry of 0 for the page_id will fail, so use NULL
321 if ( $this->mAttribs['rc_cur_id'] == 0 ) {
322 unset( $this->mAttribs['rc_cur_id'] );
323 }
324
325 # Insert new row
326 $dbw->insert( 'recentchanges', $this->mAttribs, __METHOD__ );
327
328 # Set the ID
329 $this->mAttribs['rc_id'] = $dbw->insertId();
330
331 # Notify extensions
332 // Avoid PHP 7.1 warning from passing $this by reference
333 $rc = $this;
334 Hooks::run( 'RecentChange_save', [ &$rc ] );
335
336 if ( count( $this->tags ) ) {
337 ChangeTags::addTags( $this->tags, $this->mAttribs['rc_id'],
338 $this->mAttribs['rc_this_oldid'], $this->mAttribs['rc_logid'], null, $this );
339 }
340
341 # Notify external application via UDP
342 if ( !$noudp ) {
343 $this->notifyRCFeeds();
344 }
345
346 # E-mail notifications
347 if ( $wgUseEnotif || $wgShowUpdatedMarker ) {
348 $editor = $this->getPerformer();
349 $title = $this->getTitle();
350
351 // Never send an RC notification email about categorization changes
352 if (
353 $this->mAttribs['rc_type'] != RC_CATEGORIZE &&
354 Hooks::run( 'AbortEmailNotification', [ $editor, $title, $this ] )
355 ) {
356 // @FIXME: This would be better as an extension hook
357 // Send emails or email jobs once this row is safely committed
358 $dbw->onTransactionIdle(
359 function () use ( $editor, $title ) {
360 $enotif = new EmailNotification();
361 $enotif->notifyOnPageChange(
362 $editor,
363 $title,
364 $this->mAttribs['rc_timestamp'],
365 $this->mAttribs['rc_comment'],
366 $this->mAttribs['rc_minor'],
367 $this->mAttribs['rc_last_oldid'],
368 $this->mExtra['pageStatus']
369 );
370 },
371 __METHOD__
372 );
373 }
374 }
375
376 // Update the cached list of active users
377 if ( $this->mAttribs['rc_user'] > 0 ) {
379 }
380 }
381
386 public function notifyRCFeeds( array $feeds = null ) {
388 if ( $feeds === null ) {
389 $feeds = $wgRCFeeds;
390 }
391
392 $performer = $this->getPerformer();
393
394 foreach ( $feeds as $feed ) {
395 $feed += [
396 'omit_bots' => false,
397 'omit_anon' => false,
398 'omit_user' => false,
399 'omit_minor' => false,
400 'omit_patrolled' => false,
401 ];
402
403 if (
404 ( $feed['omit_bots'] && $this->mAttribs['rc_bot'] ) ||
405 ( $feed['omit_anon'] && $performer->isAnon() ) ||
406 ( $feed['omit_user'] && !$performer->isAnon() ) ||
407 ( $feed['omit_minor'] && $this->mAttribs['rc_minor'] ) ||
408 ( $feed['omit_patrolled'] && $this->mAttribs['rc_patrolled'] ) ||
409 $this->mAttribs['rc_type'] == RC_EXTERNAL
410 ) {
411 continue;
412 }
413
414 $engine = self::getEngine( $feed['uri'] );
415
416 if ( isset( $this->mExtra['actionCommentIRC'] ) ) {
417 $actionComment = $this->mExtra['actionCommentIRC'];
418 } else {
419 $actionComment = null;
420 }
421
423 $formatter = is_object( $feed['formatter'] ) ? $feed['formatter'] : new $feed['formatter']();
424 $line = $formatter->getLine( $feed, $this, $actionComment );
425 if ( !$line ) {
426 // T109544
427 // If a feed formatter returns null, this will otherwise cause an
428 // error in at least RedisPubSubFeedEngine.
429 // Not sure where/how this should best be handled.
430 continue;
431 }
432
433 $engine->send( $feed, $line );
434 }
435 }
436
444 public static function getEngine( $uri ) {
446
447 $scheme = parse_url( $uri, PHP_URL_SCHEME );
448 if ( !$scheme ) {
449 throw new MWException( __FUNCTION__ . ": Invalid stream logger URI: '$uri'" );
450 }
451
452 if ( !isset( $wgRCEngines[$scheme] ) ) {
453 throw new MWException( __FUNCTION__ . ": Unknown stream logger URI scheme: $scheme" );
454 }
455
456 return new $wgRCEngines[$scheme];
457 }
458
468 public static function markPatrolled( $change, $auto = false, $tags = null ) {
470
471 $change = $change instanceof RecentChange
472 ? $change
473 : RecentChange::newFromId( $change );
474
475 if ( !$change instanceof RecentChange ) {
476 return null;
477 }
478
479 return $change->doMarkPatrolled( $wgUser, $auto, $tags );
480 }
481
493 public function doMarkPatrolled( User $user, $auto = false, $tags = null ) {
495
496 $errors = [];
497 // If recentchanges patrol is disabled, only new pages or new file versions
498 // can be patrolled, provided the appropriate config variable is set
499 if ( !$wgUseRCPatrol && ( !$wgUseNPPatrol || $this->getAttribute( 'rc_type' ) != RC_NEW ) &&
500 ( !$wgUseFilePatrol || !( $this->getAttribute( 'rc_type' ) == RC_LOG &&
501 $this->getAttribute( 'rc_log_type' ) == 'upload' ) ) ) {
502 $errors[] = [ 'rcpatroldisabled' ];
503 }
504 // Automatic patrol needs "autopatrol", ordinary patrol needs "patrol"
505 $right = $auto ? 'autopatrol' : 'patrol';
506 $errors = array_merge( $errors, $this->getTitle()->getUserPermissionsErrors( $right, $user ) );
507 if ( !Hooks::run( 'MarkPatrolled',
508 [ $this->getAttribute( 'rc_id' ), &$user, false, $auto ] )
509 ) {
510 $errors[] = [ 'hookaborted' ];
511 }
512 // Users without the 'autopatrol' right can't patrol their
513 // own revisions
514 if ( $user->getName() === $this->getAttribute( 'rc_user_text' )
515 && !$user->isAllowed( 'autopatrol' )
516 ) {
517 $errors[] = [ 'markedaspatrollederror-noautopatrol' ];
518 }
519 if ( $errors ) {
520 return $errors;
521 }
522 // If the change was patrolled already, do nothing
523 if ( $this->getAttribute( 'rc_patrolled' ) ) {
524 return [];
525 }
526 // Actually set the 'patrolled' flag in RC
527 $this->reallyMarkPatrolled();
528 // Log this patrol event
530
531 Hooks::run(
532 'MarkPatrolledComplete',
533 [ $this->getAttribute( 'rc_id' ), &$user, false, $auto ]
534 );
535
536 return [];
537 }
538
543 public function reallyMarkPatrolled() {
544 $dbw = wfGetDB( DB_MASTER );
545 $dbw->update(
546 'recentchanges',
547 [
548 'rc_patrolled' => 1
549 ],
550 [
551 'rc_id' => $this->getAttribute( 'rc_id' )
552 ],
553 __METHOD__
554 );
555 // Invalidate the page cache after the page has been patrolled
556 // to make sure that the Patrol link isn't visible any longer!
557 $this->getTitle()->invalidateCache();
558
559 return $dbw->affectedRows();
560 }
561
581 public static function notifyEdit(
582 $timestamp, &$title, $minor, &$user, $comment, $oldId, $lastTimestamp,
583 $bot, $ip = '', $oldSize = 0, $newSize = 0, $newId = 0, $patrol = 0,
584 $tags = []
585 ) {
586 $rc = new RecentChange;
587 $rc->mTitle = $title;
588 $rc->mPerformer = $user;
589 $rc->mAttribs = [
590 'rc_timestamp' => $timestamp,
591 'rc_namespace' => $title->getNamespace(),
592 'rc_title' => $title->getDBkey(),
593 'rc_type' => RC_EDIT,
594 'rc_source' => self::SRC_EDIT,
595 'rc_minor' => $minor ? 1 : 0,
596 'rc_cur_id' => $title->getArticleID(),
597 'rc_user' => $user->getId(),
598 'rc_user_text' => $user->getName(),
599 'rc_comment' => $comment,
600 'rc_this_oldid' => $newId,
601 'rc_last_oldid' => $oldId,
602 'rc_bot' => $bot ? 1 : 0,
603 'rc_ip' => self::checkIPAddress( $ip ),
604 'rc_patrolled' => intval( $patrol ),
605 'rc_new' => 0, # obsolete
606 'rc_old_len' => $oldSize,
607 'rc_new_len' => $newSize,
608 'rc_deleted' => 0,
609 'rc_logid' => 0,
610 'rc_log_type' => null,
611 'rc_log_action' => '',
612 'rc_params' => ''
613 ];
614
615 $rc->mExtra = [
616 'prefixedDBkey' => $title->getPrefixedDBkey(),
617 'lastTimestamp' => $lastTimestamp,
618 'oldSize' => $oldSize,
619 'newSize' => $newSize,
620 'pageStatus' => 'changed'
621 ];
622
623 DeferredUpdates::addCallableUpdate(
624 function () use ( $rc, $tags ) {
625 $rc->addTags( $tags );
626 $rc->save();
627 if ( $rc->mAttribs['rc_patrolled'] ) {
628 PatrolLog::record( $rc, true, $rc->getPerformer() );
629 }
630 },
631 DeferredUpdates::POSTSEND,
633 );
634
635 return $rc;
636 }
637
655 public static function notifyNew(
656 $timestamp, &$title, $minor, &$user, $comment, $bot,
657 $ip = '', $size = 0, $newId = 0, $patrol = 0, $tags = []
658 ) {
659 $rc = new RecentChange;
660 $rc->mTitle = $title;
661 $rc->mPerformer = $user;
662 $rc->mAttribs = [
663 'rc_timestamp' => $timestamp,
664 'rc_namespace' => $title->getNamespace(),
665 'rc_title' => $title->getDBkey(),
666 'rc_type' => RC_NEW,
667 'rc_source' => self::SRC_NEW,
668 'rc_minor' => $minor ? 1 : 0,
669 'rc_cur_id' => $title->getArticleID(),
670 'rc_user' => $user->getId(),
671 'rc_user_text' => $user->getName(),
672 'rc_comment' => $comment,
673 'rc_this_oldid' => $newId,
674 'rc_last_oldid' => 0,
675 'rc_bot' => $bot ? 1 : 0,
676 'rc_ip' => self::checkIPAddress( $ip ),
677 'rc_patrolled' => intval( $patrol ),
678 'rc_new' => 1, # obsolete
679 'rc_old_len' => 0,
680 'rc_new_len' => $size,
681 'rc_deleted' => 0,
682 'rc_logid' => 0,
683 'rc_log_type' => null,
684 'rc_log_action' => '',
685 'rc_params' => ''
686 ];
687
688 $rc->mExtra = [
689 'prefixedDBkey' => $title->getPrefixedDBkey(),
690 'lastTimestamp' => 0,
691 'oldSize' => 0,
692 'newSize' => $size,
693 'pageStatus' => 'created'
694 ];
695
696 DeferredUpdates::addCallableUpdate(
697 function () use ( $rc, $tags ) {
698 $rc->addTags( $tags );
699 $rc->save();
700 if ( $rc->mAttribs['rc_patrolled'] ) {
701 PatrolLog::record( $rc, true, $rc->getPerformer() );
702 }
703 },
704 DeferredUpdates::POSTSEND,
706 );
707
708 return $rc;
709 }
710
726 public static function notifyLog( $timestamp, &$title, &$user, $actionComment, $ip, $type,
727 $action, $target, $logComment, $params, $newId = 0, $actionCommentIRC = ''
728 ) {
730
731 # Don't add private logs to RC!
732 if ( isset( $wgLogRestrictions[$type] ) && $wgLogRestrictions[$type] != '*' ) {
733 return false;
734 }
735 $rc = self::newLogEntry( $timestamp, $title, $user, $actionComment, $ip, $type, $action,
736 $target, $logComment, $params, $newId, $actionCommentIRC );
737 $rc->save();
738
739 return true;
740 }
741
759 public static function newLogEntry( $timestamp, &$title, &$user, $actionComment, $ip,
760 $type, $action, $target, $logComment, $params, $newId = 0, $actionCommentIRC = '',
761 $revId = 0, $isPatrollable = false ) {
763
764 # # Get pageStatus for email notification
765 switch ( $type . '-' . $action ) {
766 case 'delete-delete':
767 case 'delete-delete_redir':
768 $pageStatus = 'deleted';
769 break;
770 case 'move-move':
771 case 'move-move_redir':
772 $pageStatus = 'moved';
773 break;
774 case 'delete-restore':
775 $pageStatus = 'restored';
776 break;
777 case 'upload-upload':
778 $pageStatus = 'created';
779 break;
780 case 'upload-overwrite':
781 default:
782 $pageStatus = 'changed';
783 break;
784 }
785
786 // Allow unpatrolled status for patrollable log entries
787 $markPatrolled = $isPatrollable ? $user->isAllowed( 'autopatrol' ) : true;
788
789 $rc = new RecentChange;
790 $rc->mTitle = $target;
791 $rc->mPerformer = $user;
792 $rc->mAttribs = [
793 'rc_timestamp' => $timestamp,
794 'rc_namespace' => $target->getNamespace(),
795 'rc_title' => $target->getDBkey(),
796 'rc_type' => RC_LOG,
797 'rc_source' => self::SRC_LOG,
798 'rc_minor' => 0,
799 'rc_cur_id' => $target->getArticleID(),
800 'rc_user' => $user->getId(),
801 'rc_user_text' => $user->getName(),
802 'rc_comment' => $logComment,
803 'rc_this_oldid' => $revId,
804 'rc_last_oldid' => 0,
805 'rc_bot' => $user->isAllowed( 'bot' ) ? (int)$wgRequest->getBool( 'bot', true ) : 0,
806 'rc_ip' => self::checkIPAddress( $ip ),
807 'rc_patrolled' => $markPatrolled ? 1 : 0,
808 'rc_new' => 0, # obsolete
809 'rc_old_len' => null,
810 'rc_new_len' => null,
811 'rc_deleted' => 0,
812 'rc_logid' => $newId,
813 'rc_log_type' => $type,
814 'rc_log_action' => $action,
815 'rc_params' => $params
816 ];
817
818 $rc->mExtra = [
819 'prefixedDBkey' => $title->getPrefixedDBkey(),
820 'lastTimestamp' => 0,
821 'actionComment' => $actionComment, // the comment appended to the action, passed from LogPage
822 'pageStatus' => $pageStatus,
823 'actionCommentIRC' => $actionCommentIRC
824 ];
825
826 return $rc;
827 }
828
849 public static function newForCategorization(
851 Title $categoryTitle,
852 User $user = null,
853 $comment,
854 Title $pageTitle,
855 $oldRevId,
856 $newRevId,
857 $lastTimestamp,
858 $bot,
859 $ip = '',
860 $deleted = 0
861 ) {
862 $rc = new RecentChange;
863 $rc->mTitle = $categoryTitle;
864 $rc->mPerformer = $user;
865 $rc->mAttribs = [
866 'rc_timestamp' => $timestamp,
867 'rc_namespace' => $categoryTitle->getNamespace(),
868 'rc_title' => $categoryTitle->getDBkey(),
869 'rc_type' => RC_CATEGORIZE,
870 'rc_source' => self::SRC_CATEGORIZE,
871 'rc_minor' => 0,
872 'rc_cur_id' => $pageTitle->getArticleID(),
873 'rc_user' => $user ? $user->getId() : 0,
874 'rc_user_text' => $user ? $user->getName() : '',
875 'rc_comment' => $comment,
876 'rc_this_oldid' => $newRevId,
877 'rc_last_oldid' => $oldRevId,
878 'rc_bot' => $bot ? 1 : 0,
879 'rc_ip' => self::checkIPAddress( $ip ),
880 'rc_patrolled' => 1, // Always patrolled, just like log entries
881 'rc_new' => 0, # obsolete
882 'rc_old_len' => null,
883 'rc_new_len' => null,
884 'rc_deleted' => $deleted,
885 'rc_logid' => 0,
886 'rc_log_type' => null,
887 'rc_log_action' => '',
888 'rc_params' => serialize( [
889 'hidden-cat' => WikiCategoryPage::factory( $categoryTitle )->isHidden()
890 ] )
891 ];
892
893 $rc->mExtra = [
894 'prefixedDBkey' => $categoryTitle->getPrefixedDBkey(),
895 'lastTimestamp' => $lastTimestamp,
896 'oldSize' => 0,
897 'newSize' => 0,
898 'pageStatus' => 'changed'
899 ];
900
901 return $rc;
902 }
903
912 public function getParam( $name ) {
913 $params = $this->parseParams();
914 return isset( $params[$name] ) ? $params[$name] : null;
915 }
916
922 public function loadFromRow( $row ) {
923 $this->mAttribs = get_object_vars( $row );
924 $this->mAttribs['rc_timestamp'] = wfTimestamp( TS_MW, $this->mAttribs['rc_timestamp'] );
925 $this->mAttribs['rc_deleted'] = $row->rc_deleted; // MUST be set
926 }
927
934 public function getAttribute( $name ) {
935 return isset( $this->mAttribs[$name] ) ? $this->mAttribs[$name] : null;
936 }
937
941 public function getAttributes() {
942 return $this->mAttribs;
943 }
944
951 public function diffLinkTrail( $forceCur ) {
952 if ( $this->mAttribs['rc_type'] == RC_EDIT ) {
953 $trail = "curid=" . (int)( $this->mAttribs['rc_cur_id'] ) .
954 "&oldid=" . (int)( $this->mAttribs['rc_last_oldid'] );
955 if ( $forceCur ) {
956 $trail .= '&diff=0';
957 } else {
958 $trail .= '&diff=' . (int)( $this->mAttribs['rc_this_oldid'] );
959 }
960 } else {
961 $trail = '';
962 }
963
964 return $trail;
965 }
966
974 public function getCharacterDifference( $old = 0, $new = 0 ) {
975 if ( $old === 0 ) {
976 $old = $this->mAttribs['rc_old_len'];
977 }
978 if ( $new === 0 ) {
979 $new = $this->mAttribs['rc_new_len'];
980 }
981 if ( $old === null || $new === null ) {
982 return '';
983 }
984
985 return ChangesList::showCharacterDifference( $old, $new );
986 }
987
988 private static function checkIPAddress( $ip ) {
990 if ( $ip ) {
991 if ( !IP::isIPAddress( $ip ) ) {
992 throw new MWException( "Attempt to write \"" . $ip .
993 "\" as an IP address into recent changes" );
994 }
995 } else {
996 $ip = $wgRequest->getIP();
997 if ( !$ip ) {
998 $ip = '';
999 }
1000 }
1001
1002 return $ip;
1003 }
1004
1014 public static function isInRCLifespan( $timestamp, $tolerance = 0 ) {
1016
1017 return wfTimestamp( TS_UNIX, $timestamp ) > time() - $tolerance - $wgRCMaxAge;
1018 }
1019
1027 public function parseParams() {
1028 $rcParams = $this->getAttribute( 'rc_params' );
1029
1030 MediaWiki\suppressWarnings();
1031 $unserializedParams = unserialize( $rcParams );
1032 MediaWiki\restoreWarnings();
1033
1034 return $unserializedParams;
1035 }
1036
1045 public function addTags( $tags ) {
1046 if ( is_string( $tags ) ) {
1047 $this->tags[] = $tags;
1048 } else {
1049 $this->tags = array_merge( $tags, $this->tags );
1050 }
1051 }
1052}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
serialize()
unserialize( $serialized)
$wgRCFeeds
Recentchanges items are periodically purged; entries older than this many seconds will go.
$wgPutIPinRC
Log IP addresses in the recentchanges table; can be accessed only by extensions (e....
$wgUseFilePatrol
Use file patrolling to check new files on Special:Newfiles.
$wgLogRestrictions
This restricts log access to those who have a certain right Users without this will not see it in the...
$wgShowUpdatedMarker
Show "Updated (since my last visit)" marker in RC view, watchlist and history view for watched pages ...
$wgUseRCPatrol
Use RC Patrolling to check for vandalism (from recent changes and watchlists) New pages and new files...
$wgUseNPPatrol
Use new page patrolling to check new pages on Special:Newpages.
$wgRCMaxAge
Recentchanges items are periodically purged; entries older than this many seconds will go.
$wgRCEngines
Used by RecentChange::getEngine to find the correct engine to use for a given URI scheme.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$wgUser
Definition Setup.php:806
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition Setup.php:36
$wgUseEnotif
Definition Setup.php:343
if(! $wgDBerrorLogTZ) $wgRequest
Definition Setup.php:664
$line
Definition cdb.php:59
static addTags( $tags, $rc_id=null, $rev_id=null, $log_id=null, $params=null, RecentChange $rc=null)
Add tags to a change given its rc_id, rev_id and/or log_id.
static showCharacterDifference( $old, $new, IContextSource $context=null)
Show formatted char difference.
This module processes the email notifications when the current page is changed.
static isIPAddress( $ip)
Determine if a string is as valid IP address or network (CIDR prefix).
Definition IP.php:79
static singleton( $wiki=false)
MediaWiki exception.
static record( $rc, $auto=false, User $user=null, $tags=null)
Record a log event for a change being patrolled.
Definition PatrolLog.php:41
Utility class for creating new RC entries.
setExtra( $extra)
static parseToRCType( $type)
Parsing text to RC_* constants.
reallyMarkPatrolled()
Mark this RecentChange patrolled, without error checking.
static getEngine( $uri)
Gets the stream engine object for a given URI from $wgRCEngines.
static newFromRow( $row)
parseParams()
Parses and returns the rc_params attribute.
static array $changeTypes
Array of change types.
static selectFields()
Return the list of recentchanges fields that should be selected to create a new recentchanges object.
const SRC_CATEGORIZE
getPerformer()
Get the User object of the person who performed this change.
static checkIPAddress( $ip)
static getChangeTypes()
Get an array of all change types.
static isInRCLifespan( $timestamp, $tolerance=0)
Check whether the given timestamp is new enough to have a RC row with a given tolerance as the recent...
static newForCategorization( $timestamp, Title $categoryTitle, User $user=null, $comment, Title $pageTitle, $oldRevId, $newRevId, $lastTimestamp, $bot, $ip='', $deleted=0)
Constructs a RecentChange object for the given categorization This does not call save() on the object...
static markPatrolled( $change, $auto=false, $tags=null)
Mark a given change as patrolled.
int $counter
Line number of recent change.
doMarkPatrolled(User $user, $auto=false, $tags=null)
Mark this RecentChange as patrolled.
static newLogEntry( $timestamp, &$title, &$user, $actionComment, $ip, $type, $action, $target, $logComment, $params, $newId=0, $actionCommentIRC='', $revId=0, $isPatrollable=false)
setAttribs( $attribs)
static newFromConds( $conds, $fname=__METHOD__, $dbType=DB_REPLICA)
Find the first recent change matching some specific conditions.
getCharacterDifference( $old=0, $new=0)
Returns the change size (HTML).
static parseFromRCType( $rcType)
Parsing RC_* constants to human-readable test.
notifyRCFeeds(array $feeds=null)
Notify all the feeds about the change.
save( $noudp=false)
Writes the data in this object to the database.
array $tags
List of tags to apply.
getParam( $name)
Get a parameter value.
addTags( $tags)
Tags to append to the recent change, and associated revision/log.
static notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot, $ip='', $size=0, $newId=0, $patrol=0, $tags=[])
Makes an entry in the database corresponding to page creation Note: the title object must be loaded w...
loadFromRow( $row)
Initialises the members of this object from a mysql row object.
getAttribute( $name)
Get an attribute value.
static notifyLog( $timestamp, &$title, &$user, $actionComment, $ip, $type, $action, $target, $logComment, $params, $newId=0, $actionCommentIRC='')
static notifyEdit( $timestamp, &$title, $minor, &$user, $comment, $oldId, $lastTimestamp, $bot, $ip='', $oldSize=0, $newSize=0, $newId=0, $patrol=0, $tags=[])
Makes an entry in the database corresponding to an edit.
diffLinkTrail( $forceCur)
Gets the end part of the diff URL associated with this object Blank if no diff link should be display...
static newFromId( $rcid)
Obtain the recent change with a given rc_id value.
This is to display changes made to all articles linked in an article.
Represents a title within MediaWiki.
Definition Title.php:36
getNamespace()
Get the namespace index, i.e.
Definition Title.php:921
getPrefixedDBkey()
Get the prefixed database key form.
Definition Title.php:1443
getDBkey()
Get the main part with underscores.
Definition Title.php:898
getArticleID( $flags=0)
Get the article ID for this Title from the link cache, adding it if necessary.
Definition Title.php:3209
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:48
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition WikiPage.php:115
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the local content language as $wgContLang
Definition design.txt:57
when a variable name is used in a it is silently declared as a new local masking the global
Definition design.txt:95
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
const RC_NEW
Definition Defines.php:137
const RC_LOG
Definition Defines.php:138
const RC_EXTERNAL
Definition Defines.php:139
const RC_EDIT
Definition Defines.php:136
const RC_CATEGORIZE
Definition Defines.php:140
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context $revId
Definition hooks.txt:1095
the array() calling protocol came about after MediaWiki 1.4rc1.
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition hooks.txt:249
namespace are movable Hooks may change this value to override the return value of MWNamespace::isMovable(). 'NewDifferenceEngine' do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition hooks.txt:2568
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account incomplete not yet checked for validity & $retval
Definition hooks.txt:268
namespace and then decline to actually register it file or subcat img or subcat $title
Definition hooks.txt:986
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a message
Definition hooks.txt:2097
passed in as a query string parameter to the various URLs constructed here(i.e. $prevlink) $ldel you ll need to handle error etc yourself modifying $error and returning true will cause the contents of $error to be echoed at the top of the edit form as wikitext Return true without altering $error to allow the edit to proceed & $editor
Definition hooks.txt:1377
return true to allow those checks to and false if checking is done remove or add to the links of a group of changes in EnhancedChangesList Hook subscribers can return false to omit this line from recentchanges use this to change the tables headers temp or archived zone change it to an object instance and return false override the list derivative used the name of the old file when set the default code will be skipped true if there is text before this autocomment $auto
Definition hooks.txt:1554
null for the local wiki Added in
Definition hooks.txt:1558
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing & $attribs
Definition hooks.txt:1958
the value to return A Title object or null for latest all implement SearchIndexField $engine
Definition hooks.txt:2755
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:304
$comment
if( $limit) $timestamp
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37
const DB_REPLICA
Definition defines.php:22
const DB_MASTER
Definition defines.php:23
$params
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
Definition defines.php:6
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition defines.php:11