MediaWiki REL1_28
Block.php
Go to the documentation of this file.
1<?php
24
25class Block {
27 public $mReason;
28
31
33 public $mAuto;
34
36 public $mExpiry;
37
39 public $mHideName;
40
43
45 protected $mId;
46
48 protected $mFromMaster;
49
51 protected $mBlockEmail;
52
55
57 protected $mCreateAccount;
58
60 protected $target;
61
63 protected $forcedTargetID;
64
66 protected $type;
67
69 protected $blocker;
70
72 protected $isHardblock;
73
75 protected $isAutoblocking;
76
77 # TYPE constants
78 const TYPE_USER = 1;
79 const TYPE_IP = 2;
80 const TYPE_RANGE = 3;
81 const TYPE_AUTO = 4;
82 const TYPE_ID = 5;
83
106 function __construct( $options = [] ) {
107 $defaults = [
108 'address' => '',
109 'user' => null,
110 'by' => null,
111 'reason' => '',
112 'timestamp' => '',
113 'auto' => false,
114 'expiry' => '',
115 'anonOnly' => false,
116 'createAccount' => false,
117 'enableAutoblock' => false,
118 'hideName' => false,
119 'blockEmail' => false,
120 'allowUsertalk' => false,
121 'byText' => '',
122 ];
123
124 if ( func_num_args() > 1 || !is_array( $options ) ) {
125 $options = array_combine(
126 array_slice( array_keys( $defaults ), 0, func_num_args() ),
127 func_get_args()
128 );
129 wfDeprecated( __METHOD__ . ' with multiple arguments', '1.26' );
130 }
131
132 $options += $defaults;
133
134 $this->setTarget( $options['address'] );
135
136 if ( $this->target instanceof User && $options['user'] ) {
137 # Needed for foreign users
138 $this->forcedTargetID = $options['user'];
139 }
140
141 if ( $options['by'] ) {
142 # Local user
143 $this->setBlocker( User::newFromId( $options['by'] ) );
144 } else {
145 # Foreign user
146 $this->setBlocker( $options['byText'] );
147 }
148
149 $this->mReason = $options['reason'];
150 $this->mTimestamp = wfTimestamp( TS_MW, $options['timestamp'] );
151 $this->mExpiry = wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] );
152
153 # Boolean settings
154 $this->mAuto = (bool)$options['auto'];
155 $this->mHideName = (bool)$options['hideName'];
156 $this->isHardblock( !$options['anonOnly'] );
157 $this->isAutoblocking( (bool)$options['enableAutoblock'] );
158
159 # Prevention measures
160 $this->prevents( 'sendemail', (bool)$options['blockEmail'] );
161 $this->prevents( 'editownusertalk', !$options['allowUsertalk'] );
162 $this->prevents( 'createaccount', (bool)$options['createAccount'] );
163
164 $this->mFromMaster = false;
165 }
166
173 public static function newFromID( $id ) {
175 $res = $dbr->selectRow(
176 'ipblocks',
177 self::selectFields(),
178 [ 'ipb_id' => $id ],
179 __METHOD__
180 );
181 if ( $res ) {
182 return self::newFromRow( $res );
183 } else {
184 return null;
185 }
186 }
187
193 public static function selectFields() {
194 return [
195 'ipb_id',
196 'ipb_address',
197 'ipb_by',
198 'ipb_by_text',
199 'ipb_reason',
200 'ipb_timestamp',
201 'ipb_auto',
202 'ipb_anon_only',
203 'ipb_create_account',
204 'ipb_enable_autoblock',
205 'ipb_expiry',
206 'ipb_deleted',
207 'ipb_block_email',
208 'ipb_allow_usertalk',
209 'ipb_parent_block_id',
210 ];
211 }
212
221 public function equals( Block $block ) {
222 return (
223 (string)$this->target == (string)$block->target
224 && $this->type == $block->type
225 && $this->mAuto == $block->mAuto
226 && $this->isHardblock() == $block->isHardblock()
227 && $this->prevents( 'createaccount' ) == $block->prevents( 'createaccount' )
228 && $this->mExpiry == $block->mExpiry
229 && $this->isAutoblocking() == $block->isAutoblocking()
230 && $this->mHideName == $block->mHideName
231 && $this->prevents( 'sendemail' ) == $block->prevents( 'sendemail' )
232 && $this->prevents( 'editownusertalk' ) == $block->prevents( 'editownusertalk' )
233 && $this->mReason == $block->mReason
234 );
235 }
236
247 protected function newLoad( $vagueTarget = null ) {
248 $db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_REPLICA );
249
250 if ( $this->type !== null ) {
251 $conds = [
252 'ipb_address' => [ (string)$this->target ],
253 ];
254 } else {
255 $conds = [ 'ipb_address' => [] ];
256 }
257
258 # Be aware that the != '' check is explicit, since empty values will be
259 # passed by some callers (bug 29116)
260 if ( $vagueTarget != '' ) {
261 list( $target, $type ) = self::parseTarget( $vagueTarget );
262 switch ( $type ) {
263 case self::TYPE_USER:
264 # Slightly weird, but who are we to argue?
265 $conds['ipb_address'][] = (string)$target;
266 break;
267
268 case self::TYPE_IP:
269 $conds['ipb_address'][] = (string)$target;
270 $conds[] = self::getRangeCond( IP::toHex( $target ) );
271 $conds = $db->makeList( $conds, LIST_OR );
272 break;
273
274 case self::TYPE_RANGE:
275 list( $start, $end ) = IP::parseRange( $target );
276 $conds['ipb_address'][] = (string)$target;
277 $conds[] = self::getRangeCond( $start, $end );
278 $conds = $db->makeList( $conds, LIST_OR );
279 break;
280
281 default:
282 throw new MWException( "Tried to load block with invalid type" );
283 }
284 }
285
286 $res = $db->select( 'ipblocks', self::selectFields(), $conds, __METHOD__ );
287
288 # This result could contain a block on the user, a block on the IP, and a russian-doll
289 # set of rangeblocks. We want to choose the most specific one, so keep a leader board.
290 $bestRow = null;
291
292 # Lower will be better
293 $bestBlockScore = 100;
294
295 # This is begging for $this = $bestBlock, but that's not allowed in PHP :(
296 $bestBlockPreventsEdit = null;
297
298 foreach ( $res as $row ) {
299 $block = self::newFromRow( $row );
300
301 # Don't use expired blocks
302 if ( $block->isExpired() ) {
303 continue;
304 }
305
306 # Don't use anon only blocks on users
307 if ( $this->type == self::TYPE_USER && !$block->isHardblock() ) {
308 continue;
309 }
310
311 if ( $block->getType() == self::TYPE_RANGE ) {
312 # This is the number of bits that are allowed to vary in the block, give
313 # or take some floating point errors
314 $end = Wikimedia\base_convert( $block->getRangeEnd(), 16, 10 );
315 $start = Wikimedia\base_convert( $block->getRangeStart(), 16, 10 );
316 $size = log( $end - $start + 1, 2 );
317
318 # This has the nice property that a /32 block is ranked equally with a
319 # single-IP block, which is exactly what it is...
320 $score = self::TYPE_RANGE - 1 + ( $size / 128 );
321
322 } else {
323 $score = $block->getType();
324 }
325
326 if ( $score < $bestBlockScore ) {
327 $bestBlockScore = $score;
328 $bestRow = $row;
329 $bestBlockPreventsEdit = $block->prevents( 'edit' );
330 }
331 }
332
333 if ( $bestRow !== null ) {
334 $this->initFromRow( $bestRow );
335 $this->prevents( 'edit', $bestBlockPreventsEdit );
336 return true;
337 } else {
338 return false;
339 }
340 }
341
348 public static function getRangeCond( $start, $end = null ) {
349 if ( $end === null ) {
350 $end = $start;
351 }
352 # Per bug 14634, we want to include relevant active rangeblocks; for
353 # rangeblocks, we want to include larger ranges which enclose the given
354 # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
355 # so we can improve performance by filtering on a LIKE clause
356 $chunk = self::getIpFragment( $start );
358 $like = $dbr->buildLike( $chunk, $dbr->anyString() );
359
360 # Fairly hard to make a malicious SQL statement out of hex characters,
361 # but stranger things have happened...
362 $safeStart = $dbr->addQuotes( $start );
363 $safeEnd = $dbr->addQuotes( $end );
364
365 return $dbr->makeList(
366 [
367 "ipb_range_start $like",
368 "ipb_range_start <= $safeStart",
369 "ipb_range_end >= $safeEnd",
370 ],
372 );
373 }
374
381 protected static function getIpFragment( $hex ) {
383 if ( substr( $hex, 0, 3 ) == 'v6-' ) {
384 return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
385 } else {
386 return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
387 }
388 }
389
395 protected function initFromRow( $row ) {
396 $this->setTarget( $row->ipb_address );
397 if ( $row->ipb_by ) { // local user
398 $this->setBlocker( User::newFromId( $row->ipb_by ) );
399 } else { // foreign user
400 $this->setBlocker( $row->ipb_by_text );
401 }
402
403 $this->mReason = $row->ipb_reason;
404 $this->mTimestamp = wfTimestamp( TS_MW, $row->ipb_timestamp );
405 $this->mAuto = $row->ipb_auto;
406 $this->mHideName = $row->ipb_deleted;
407 $this->mId = (int)$row->ipb_id;
408 $this->mParentBlockId = $row->ipb_parent_block_id;
409
410 // I wish I didn't have to do this
411 $this->mExpiry = wfGetDB( DB_REPLICA )->decodeExpiry( $row->ipb_expiry );
412
413 $this->isHardblock( !$row->ipb_anon_only );
414 $this->isAutoblocking( $row->ipb_enable_autoblock );
415
416 $this->prevents( 'createaccount', $row->ipb_create_account );
417 $this->prevents( 'sendemail', $row->ipb_block_email );
418 $this->prevents( 'editownusertalk', !$row->ipb_allow_usertalk );
419 }
420
426 public static function newFromRow( $row ) {
427 $block = new Block;
428 $block->initFromRow( $row );
429 return $block;
430 }
431
438 public function delete() {
439 if ( wfReadOnly() ) {
440 return false;
441 }
442
443 if ( !$this->getId() ) {
444 throw new MWException( "Block::delete() requires that the mId member be filled\n" );
445 }
446
447 $dbw = wfGetDB( DB_MASTER );
448 $dbw->delete( 'ipblocks', [ 'ipb_parent_block_id' => $this->getId() ], __METHOD__ );
449 $dbw->delete( 'ipblocks', [ 'ipb_id' => $this->getId() ], __METHOD__ );
450
451 return $dbw->affectedRows() > 0;
452 }
453
462 public function insert( $dbw = null ) {
464 wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" );
465
466 if ( $dbw === null ) {
467 $dbw = wfGetDB( DB_MASTER );
468 }
469
470 # Periodic purge via commit hooks
471 if ( mt_rand( 0, 9 ) == 0 ) {
473 }
474
475 $row = $this->getDatabaseArray();
476 $row['ipb_id'] = $dbw->nextSequenceValue( "ipblocks_ipb_id_seq" );
477
478 $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
479 $affected = $dbw->affectedRows();
480 $this->mId = $dbw->insertId();
481
482 # Don't collide with expired blocks.
483 # Do this after trying to insert to avoid locking.
484 if ( !$affected ) {
485 # T96428: The ipb_address index uses a prefix on a field, so
486 # use a standard SELECT + DELETE to avoid annoying gap locks.
487 $ids = $dbw->selectFieldValues( 'ipblocks',
488 'ipb_id',
489 [
490 'ipb_address' => $row['ipb_address'],
491 'ipb_user' => $row['ipb_user'],
492 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() )
493 ],
494 __METHOD__
495 );
496 if ( $ids ) {
497 $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], __METHOD__ );
498 $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
499 $affected = $dbw->affectedRows();
500 $this->mId = $dbw->insertId();
501 }
502 }
503
504 if ( $affected ) {
505 $auto_ipd_ids = $this->doRetroactiveAutoblock();
506
507 if ( $wgBlockDisablesLogin && $this->target instanceof User ) {
508 // Change user login token to force them to be logged out.
509 $this->target->setToken();
510 $this->target->saveSettings();
511 }
512
513 return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
514 }
515
516 return false;
517 }
518
526 public function update() {
527 wfDebug( "Block::update; timestamp {$this->mTimestamp}\n" );
528 $dbw = wfGetDB( DB_MASTER );
529
530 $dbw->startAtomic( __METHOD__ );
531
532 $dbw->update(
533 'ipblocks',
534 $this->getDatabaseArray( $dbw ),
535 [ 'ipb_id' => $this->getId() ],
536 __METHOD__
537 );
538
539 $affected = $dbw->affectedRows();
540
541 if ( $this->isAutoblocking() ) {
542 // update corresponding autoblock(s) (bug 48813)
543 $dbw->update(
544 'ipblocks',
546 [ 'ipb_parent_block_id' => $this->getId() ],
547 __METHOD__
548 );
549 } else {
550 // autoblock no longer required, delete corresponding autoblock(s)
551 $dbw->delete(
552 'ipblocks',
553 [ 'ipb_parent_block_id' => $this->getId() ],
554 __METHOD__
555 );
556 }
557
558 $dbw->endAtomic( __METHOD__ );
559
560 if ( $affected ) {
561 $auto_ipd_ids = $this->doRetroactiveAutoblock();
562 return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
563 }
564
565 return false;
566 }
567
573 protected function getDatabaseArray( $db = null ) {
574 if ( !$db ) {
575 $db = wfGetDB( DB_REPLICA );
576 }
577 $expiry = $db->encodeExpiry( $this->mExpiry );
578
579 if ( $this->forcedTargetID ) {
581 } else {
582 $uid = $this->target instanceof User ? $this->target->getId() : 0;
583 }
584
585 $a = [
586 'ipb_address' => (string)$this->target,
587 'ipb_user' => $uid,
588 'ipb_by' => $this->getBy(),
589 'ipb_by_text' => $this->getByName(),
590 'ipb_reason' => $this->mReason,
591 'ipb_timestamp' => $db->timestamp( $this->mTimestamp ),
592 'ipb_auto' => $this->mAuto,
593 'ipb_anon_only' => !$this->isHardblock(),
594 'ipb_create_account' => $this->prevents( 'createaccount' ),
595 'ipb_enable_autoblock' => $this->isAutoblocking(),
596 'ipb_expiry' => $expiry,
597 'ipb_range_start' => $this->getRangeStart(),
598 'ipb_range_end' => $this->getRangeEnd(),
599 'ipb_deleted' => intval( $this->mHideName ), // typecast required for SQLite
600 'ipb_block_email' => $this->prevents( 'sendemail' ),
601 'ipb_allow_usertalk' => !$this->prevents( 'editownusertalk' ),
602 'ipb_parent_block_id' => $this->mParentBlockId
603 ];
604
605 return $a;
606 }
607
611 protected function getAutoblockUpdateArray() {
612 return [
613 'ipb_by' => $this->getBy(),
614 'ipb_by_text' => $this->getByName(),
615 'ipb_reason' => $this->mReason,
616 'ipb_create_account' => $this->prevents( 'createaccount' ),
617 'ipb_deleted' => (int)$this->mHideName, // typecast required for SQLite
618 'ipb_allow_usertalk' => !$this->prevents( 'editownusertalk' ),
619 ];
620 }
621
628 protected function doRetroactiveAutoblock() {
629 $blockIds = [];
630 # If autoblock is enabled, autoblock the LAST IP(s) used
631 if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
632 wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
633
634 $continue = Hooks::run(
635 'PerformRetroactiveAutoblock', [ $this, &$blockIds ] );
636
637 if ( $continue ) {
638 self::defaultRetroactiveAutoblock( $this, $blockIds );
639 }
640 }
641 return $blockIds;
642 }
643
651 protected static function defaultRetroactiveAutoblock( Block $block, array &$blockIds ) {
653
654 // No IPs are in recentchanges table, so nothing to select
655 if ( !$wgPutIPinRC ) {
656 return;
657 }
658
660
661 $options = [ 'ORDER BY' => 'rc_timestamp DESC' ];
662 $conds = [ 'rc_user_text' => (string)$block->getTarget() ];
663
664 // Just the last IP used.
665 $options['LIMIT'] = 1;
666
667 $res = $dbr->select( 'recentchanges', [ 'rc_ip' ], $conds,
668 __METHOD__, $options );
669
670 if ( !$res->numRows() ) {
671 # No results, don't autoblock anything
672 wfDebug( "No IP found to retroactively autoblock\n" );
673 } else {
674 foreach ( $res as $row ) {
675 if ( $row->rc_ip ) {
676 $id = $block->doAutoblock( $row->rc_ip );
677 if ( $id ) {
678 $blockIds[] = $id;
679 }
680 }
681 }
682 }
683 }
684
692 public static function isWhitelistedFromAutoblocks( $ip ) {
693 // Try to get the autoblock_whitelist from the cache, as it's faster
694 // than getting the msg raw and explode()'ing it.
695 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
696 $lines = $cache->getWithSetCallback(
697 wfMemcKey( 'ipb', 'autoblock', 'whitelist' ),
698 $cache::TTL_DAY,
699 function ( $curValue, &$ttl, array &$setOpts ) {
700 $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
701
702 return explode( "\n",
703 wfMessage( 'autoblock_whitelist' )->inContentLanguage()->plain() );
704 }
705 );
706
707 wfDebug( "Checking the autoblock whitelist..\n" );
708
709 foreach ( $lines as $line ) {
710 # List items only
711 if ( substr( $line, 0, 1 ) !== '*' ) {
712 continue;
713 }
714
715 $wlEntry = substr( $line, 1 );
716 $wlEntry = trim( $wlEntry );
717
718 wfDebug( "Checking $ip against $wlEntry..." );
719
720 # Is the IP in this range?
721 if ( IP::isInRange( $ip, $wlEntry ) ) {
722 wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
723 return true;
724 } else {
725 wfDebug( " No match\n" );
726 }
727 }
728
729 return false;
730 }
731
738 public function doAutoblock( $autoblockIP ) {
739 # If autoblocks are disabled, go away.
740 if ( !$this->isAutoblocking() ) {
741 return false;
742 }
743
744 # Check for presence on the autoblock whitelist.
745 if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
746 return false;
747 }
748
749 # Allow hooks to cancel the autoblock.
750 if ( !Hooks::run( 'AbortAutoblock', [ $autoblockIP, &$this ] ) ) {
751 wfDebug( "Autoblock aborted by hook.\n" );
752 return false;
753 }
754
755 # It's okay to autoblock. Go ahead and insert/update the block...
756
757 # Do not add a *new* block if the IP is already blocked.
758 $ipblock = Block::newFromTarget( $autoblockIP );
759 if ( $ipblock ) {
760 # Check if the block is an autoblock and would exceed the user block
761 # if renewed. If so, do nothing, otherwise prolong the block time...
762 if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
763 $this->mExpiry > Block::getAutoblockExpiry( $ipblock->mTimestamp )
764 ) {
765 # Reset block timestamp to now and its expiry to
766 # $wgAutoblockExpiry in the future
767 $ipblock->updateTimestamp();
768 }
769 return false;
770 }
771
772 # Make a new block object with the desired properties.
773 $autoblock = new Block;
774 wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
775 $autoblock->setTarget( $autoblockIP );
776 $autoblock->setBlocker( $this->getBlocker() );
777 $autoblock->mReason = wfMessage( 'autoblocker', $this->getTarget(), $this->mReason )
778 ->inContentLanguage()->plain();
780 $autoblock->mTimestamp = $timestamp;
781 $autoblock->mAuto = 1;
782 $autoblock->prevents( 'createaccount', $this->prevents( 'createaccount' ) );
783 # Continue suppressing the name if needed
784 $autoblock->mHideName = $this->mHideName;
785 $autoblock->prevents( 'editownusertalk', $this->prevents( 'editownusertalk' ) );
786 $autoblock->mParentBlockId = $this->mId;
787
788 if ( $this->mExpiry == 'infinity' ) {
789 # Original block was indefinite, start an autoblock now
790 $autoblock->mExpiry = Block::getAutoblockExpiry( $timestamp );
791 } else {
792 # If the user is already blocked with an expiry date, we don't
793 # want to pile on top of that.
794 $autoblock->mExpiry = min( $this->mExpiry, Block::getAutoblockExpiry( $timestamp ) );
795 }
796
797 # Insert the block...
798 $status = $autoblock->insert();
799 return $status
800 ? $status['id']
801 : false;
802 }
803
808 public function deleteIfExpired() {
809
810 if ( $this->isExpired() ) {
811 wfDebug( "Block::deleteIfExpired() -- deleting\n" );
812 $this->delete();
813 $retVal = true;
814 } else {
815 wfDebug( "Block::deleteIfExpired() -- not expired\n" );
816 $retVal = false;
817 }
818
819 return $retVal;
820 }
821
826 public function isExpired() {
828 wfDebug( "Block::isExpired() checking current " . $timestamp . " vs $this->mExpiry\n" );
829
830 if ( !$this->mExpiry ) {
831 return false;
832 } else {
833 return $timestamp > $this->mExpiry;
834 }
835 }
836
841 public function isValid() {
842 return $this->getTarget() != null;
843 }
844
848 public function updateTimestamp() {
849 if ( $this->mAuto ) {
850 $this->mTimestamp = wfTimestamp();
851 $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
852
853 $dbw = wfGetDB( DB_MASTER );
854 $dbw->update( 'ipblocks',
855 [ /* SET */
856 'ipb_timestamp' => $dbw->timestamp( $this->mTimestamp ),
857 'ipb_expiry' => $dbw->timestamp( $this->mExpiry ),
858 ],
859 [ /* WHERE */
860 'ipb_id' => $this->getId(),
861 ],
862 __METHOD__
863 );
864 }
865 }
866
872 public function getRangeStart() {
873 switch ( $this->type ) {
874 case self::TYPE_USER:
875 return '';
876 case self::TYPE_IP:
877 return IP::toHex( $this->target );
878 case self::TYPE_RANGE:
879 list( $start, /*...*/ ) = IP::parseRange( $this->target );
880 return $start;
881 default:
882 throw new MWException( "Block with invalid type" );
883 }
884 }
885
891 public function getRangeEnd() {
892 switch ( $this->type ) {
893 case self::TYPE_USER:
894 return '';
895 case self::TYPE_IP:
896 return IP::toHex( $this->target );
897 case self::TYPE_RANGE:
898 list( /*...*/, $end ) = IP::parseRange( $this->target );
899 return $end;
900 default:
901 throw new MWException( "Block with invalid type" );
902 }
903 }
904
910 public function getBy() {
911 $blocker = $this->getBlocker();
912 return ( $blocker instanceof User )
913 ? $blocker->getId()
914 : 0;
915 }
916
922 public function getByName() {
923 $blocker = $this->getBlocker();
924 return ( $blocker instanceof User )
925 ? $blocker->getName()
926 : (string)$blocker; // username
927 }
928
933 public function getId() {
934 return $this->mId;
935 }
936
943 public function fromMaster( $x = null ) {
944 return wfSetVar( $this->mFromMaster, $x );
945 }
946
952 public function isHardblock( $x = null ) {
953 wfSetVar( $this->isHardblock, $x );
954
955 # You can't *not* hardblock a user
956 return $this->getType() == self::TYPE_USER
957 ? true
959 }
960
965 public function isAutoblocking( $x = null ) {
966 wfSetVar( $this->isAutoblocking, $x );
967
968 # You can't put an autoblock on an IP or range as we don't have any history to
969 # look over to get more IPs from
970 return $this->getType() == self::TYPE_USER
971 ? $this->isAutoblocking
972 : false;
973 }
974
982 public function prevents( $action, $x = null ) {
984 $res = null;
985 switch ( $action ) {
986 case 'edit':
987 # For now... <evil laugh>
988 $res = true;
989 break;
990 case 'createaccount':
991 $res = wfSetVar( $this->mCreateAccount, $x );
992 break;
993 case 'sendemail':
994 $res = wfSetVar( $this->mBlockEmail, $x );
995 break;
996 case 'editownusertalk':
997 $res = wfSetVar( $this->mDisableUsertalk, $x );
998 break;
999 case 'read':
1000 $res = false;
1001 break;
1002 }
1003 if ( !$res && $wgBlockDisablesLogin ) {
1004 // If a block would disable login, then it should
1005 // prevent any action that all users cannot do
1006 $anon = new User;
1007 $res = $anon->isAllowed( $action ) ? $res : true;
1008 }
1009
1010 return $res;
1011 }
1012
1017 public function getRedactedName() {
1018 if ( $this->mAuto ) {
1019 return Html::rawElement(
1020 'span',
1021 [ 'class' => 'mw-autoblockid' ],
1022 wfMessage( 'autoblockid', $this->mId )
1023 );
1024 } else {
1025 return htmlspecialchars( $this->getTarget() );
1026 }
1027 }
1028
1035 public static function getAutoblockExpiry( $timestamp ) {
1037
1039 }
1040
1044 public static function purgeExpired() {
1045 if ( wfReadOnly() ) {
1046 return;
1047 }
1048
1049 DeferredUpdates::addUpdate( new AtomicSectionUpdate(
1050 wfGetDB( DB_MASTER ),
1051 __METHOD__,
1052 function ( IDatabase $dbw, $fname ) {
1053 $dbw->delete(
1054 'ipblocks',
1055 [ 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
1056 $fname
1057 );
1058 }
1059 ) );
1060 }
1061
1082 public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
1083
1084 list( $target, $type ) = self::parseTarget( $specificTarget );
1085 if ( $type == Block::TYPE_ID || $type == Block::TYPE_AUTO ) {
1086 return Block::newFromID( $target );
1087
1088 } elseif ( $target === null && $vagueTarget == '' ) {
1089 # We're not going to find anything useful here
1090 # Be aware that the == '' check is explicit, since empty values will be
1091 # passed by some callers (bug 29116)
1092 return null;
1093
1094 } elseif ( in_array(
1095 $type,
1097 ) {
1098 $block = new Block();
1099 $block->fromMaster( $fromMaster );
1100
1101 if ( $type !== null ) {
1102 $block->setTarget( $target );
1103 }
1104
1105 if ( $block->newLoad( $vagueTarget ) ) {
1106 return $block;
1107 }
1108 }
1109 return null;
1110 }
1111
1122 public static function getBlocksForIPList( array $ipChain, $isAnon, $fromMaster = false ) {
1123 if ( !count( $ipChain ) ) {
1124 return [];
1125 }
1126
1127 $conds = [];
1128 $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1129 foreach ( array_unique( $ipChain ) as $ipaddr ) {
1130 # Discard invalid IP addresses. Since XFF can be spoofed and we do not
1131 # necessarily trust the header given to us, make sure that we are only
1132 # checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
1133 # Do not treat private IP spaces as special as it may be desirable for wikis
1134 # to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
1135 if ( !IP::isValid( $ipaddr ) ) {
1136 continue;
1137 }
1138 # Don't check trusted IPs (includes local squids which will be in every request)
1139 if ( $proxyLookup->isTrustedProxy( $ipaddr ) ) {
1140 continue;
1141 }
1142 # Check both the original IP (to check against single blocks), as well as build
1143 # the clause to check for rangeblocks for the given IP.
1144 $conds['ipb_address'][] = $ipaddr;
1145 $conds[] = self::getRangeCond( IP::toHex( $ipaddr ) );
1146 }
1147
1148 if ( !count( $conds ) ) {
1149 return [];
1150 }
1151
1152 if ( $fromMaster ) {
1153 $db = wfGetDB( DB_MASTER );
1154 } else {
1155 $db = wfGetDB( DB_REPLICA );
1156 }
1157 $conds = $db->makeList( $conds, LIST_OR );
1158 if ( !$isAnon ) {
1159 $conds = [ $conds, 'ipb_anon_only' => 0 ];
1160 }
1161 $selectFields = array_merge(
1162 [ 'ipb_range_start', 'ipb_range_end' ],
1164 );
1165 $rows = $db->select( 'ipblocks',
1166 $selectFields,
1167 $conds,
1168 __METHOD__
1169 );
1170
1171 $blocks = [];
1172 foreach ( $rows as $row ) {
1173 $block = self::newFromRow( $row );
1174 if ( !$block->isExpired() ) {
1175 $blocks[] = $block;
1176 }
1177 }
1178
1179 return $blocks;
1180 }
1181
1203 public static function chooseBlock( array $blocks, array $ipChain ) {
1204 if ( !count( $blocks ) ) {
1205 return null;
1206 } elseif ( count( $blocks ) == 1 ) {
1207 return $blocks[0];
1208 }
1209
1210 // Sort hard blocks before soft ones and secondarily sort blocks
1211 // that disable account creation before those that don't.
1212 usort( $blocks, function ( Block $a, Block $b ) {
1213 $aWeight = (int)$a->isHardblock() . (int)$a->prevents( 'createaccount' );
1214 $bWeight = (int)$b->isHardblock() . (int)$b->prevents( 'createaccount' );
1215 return strcmp( $bWeight, $aWeight ); // highest weight first
1216 } );
1217
1218 $blocksListExact = [
1219 'hard' => false,
1220 'disable_create' => false,
1221 'other' => false,
1222 'auto' => false
1223 ];
1224 $blocksListRange = [
1225 'hard' => false,
1226 'disable_create' => false,
1227 'other' => false,
1228 'auto' => false
1229 ];
1230 $ipChain = array_reverse( $ipChain );
1231
1233 foreach ( $blocks as $block ) {
1234 // Stop searching if we have already have a "better" block. This
1235 // is why the order of the blocks matters
1236 if ( !$block->isHardblock() && $blocksListExact['hard'] ) {
1237 break;
1238 } elseif ( !$block->prevents( 'createaccount' ) && $blocksListExact['disable_create'] ) {
1239 break;
1240 }
1241
1242 foreach ( $ipChain as $checkip ) {
1243 $checkipHex = IP::toHex( $checkip );
1244 if ( (string)$block->getTarget() === $checkip ) {
1245 if ( $block->isHardblock() ) {
1246 $blocksListExact['hard'] = $blocksListExact['hard'] ?: $block;
1247 } elseif ( $block->prevents( 'createaccount' ) ) {
1248 $blocksListExact['disable_create'] = $blocksListExact['disable_create'] ?: $block;
1249 } elseif ( $block->mAuto ) {
1250 $blocksListExact['auto'] = $blocksListExact['auto'] ?: $block;
1251 } else {
1252 $blocksListExact['other'] = $blocksListExact['other'] ?: $block;
1253 }
1254 // We found closest exact match in the ip list, so go to the next Block
1255 break;
1256 } elseif ( array_filter( $blocksListExact ) == []
1257 && $block->getRangeStart() <= $checkipHex
1258 && $block->getRangeEnd() >= $checkipHex
1259 ) {
1260 if ( $block->isHardblock() ) {
1261 $blocksListRange['hard'] = $blocksListRange['hard'] ?: $block;
1262 } elseif ( $block->prevents( 'createaccount' ) ) {
1263 $blocksListRange['disable_create'] = $blocksListRange['disable_create'] ?: $block;
1264 } elseif ( $block->mAuto ) {
1265 $blocksListRange['auto'] = $blocksListRange['auto'] ?: $block;
1266 } else {
1267 $blocksListRange['other'] = $blocksListRange['other'] ?: $block;
1268 }
1269 break;
1270 }
1271 }
1272 }
1273
1274 if ( array_filter( $blocksListExact ) == [] ) {
1275 $blocksList = &$blocksListRange;
1276 } else {
1277 $blocksList = &$blocksListExact;
1278 }
1279
1280 $chosenBlock = null;
1281 if ( $blocksList['hard'] ) {
1282 $chosenBlock = $blocksList['hard'];
1283 } elseif ( $blocksList['disable_create'] ) {
1284 $chosenBlock = $blocksList['disable_create'];
1285 } elseif ( $blocksList['other'] ) {
1286 $chosenBlock = $blocksList['other'];
1287 } elseif ( $blocksList['auto'] ) {
1288 $chosenBlock = $blocksList['auto'];
1289 } else {
1290 throw new MWException( "Proxy block found, but couldn't be classified." );
1291 }
1292
1293 return $chosenBlock;
1294 }
1295
1305 public static function parseTarget( $target ) {
1306 # We may have been through this before
1307 if ( $target instanceof User ) {
1308 if ( IP::isValid( $target->getName() ) ) {
1309 return [ $target, self::TYPE_IP ];
1310 } else {
1311 return [ $target, self::TYPE_USER ];
1312 }
1313 } elseif ( $target === null ) {
1314 return [ null, null ];
1315 }
1316
1317 $target = trim( $target );
1318
1319 if ( IP::isValid( $target ) ) {
1320 # We can still create a User if it's an IP address, but we need to turn
1321 # off validation checking (which would exclude IP addresses)
1322 return [
1323 User::newFromName( IP::sanitizeIP( $target ), false ),
1325 ];
1326
1327 } elseif ( IP::isValidBlock( $target ) ) {
1328 # Can't create a User from an IP range
1330 }
1331
1332 # Consider the possibility that this is not a username at all
1333 # but actually an old subpage (bug #29797)
1334 if ( strpos( $target, '/' ) !== false ) {
1335 # An old subpage, drill down to the user behind it
1336 $target = explode( '/', $target )[0];
1337 }
1338
1339 $userObj = User::newFromName( $target );
1340 if ( $userObj instanceof User ) {
1341 # Note that since numbers are valid usernames, a $target of "12345" will be
1342 # considered a User. If you want to pass a block ID, prepend a hash "#12345",
1343 # since hash characters are not valid in usernames or titles generally.
1344 return [ $userObj, Block::TYPE_USER ];
1345
1346 } elseif ( preg_match( '/^#\d+$/', $target ) ) {
1347 # Autoblock reference in the form "#12345"
1348 return [ substr( $target, 1 ), Block::TYPE_AUTO ];
1349
1350 } else {
1351 # WTF?
1352 return [ null, null ];
1353 }
1354 }
1355
1360 public function getType() {
1361 return $this->mAuto
1363 : $this->type;
1364 }
1365
1373 public function getTargetAndType() {
1374 return [ $this->getTarget(), $this->getType() ];
1375 }
1376
1383 public function getTarget() {
1384 return $this->target;
1385 }
1386
1392 public function getExpiry() {
1393 return $this->mExpiry;
1394 }
1395
1400 public function setTarget( $target ) {
1401 list( $this->target, $this->type ) = self::parseTarget( $target );
1402 }
1403
1408 public function getBlocker() {
1409 return $this->blocker;
1410 }
1411
1416 public function setBlocker( $user ) {
1417 $this->blocker = $user;
1418 }
1419
1428 $blocker = $this->getBlocker();
1429 if ( $blocker instanceof User ) { // local user
1430 $blockerUserpage = $blocker->getUserPage();
1431 $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
1432 } else { // foreign user
1433 $link = $blocker;
1434 }
1435
1436 $reason = $this->mReason;
1437 if ( $reason == '' ) {
1438 $reason = $context->msg( 'blockednoreason' )->text();
1439 }
1440
1441 /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
1442 * This could be a username, an IP range, or a single IP. */
1443 $intended = $this->getTarget();
1444
1445 $lang = $context->getLanguage();
1446 return [
1447 $this->mAuto ? 'autoblockedtext' : 'blockedtext',
1448 $link,
1449 $reason,
1450 $context->getRequest()->getIP(),
1451 $this->getByName(),
1452 $this->getId(),
1453 $lang->formatExpiry( $this->mExpiry ),
1454 (string)$intended,
1455 $lang->userTimeAndDate( $this->mTimestamp, $context->getUser() ),
1456 ];
1457 }
1458}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
$wgAutoblockExpiry
Number of seconds before autoblock entries expire.
$wgBlockCIDRLimit
Limits on the possible sizes of range blocks.
$wgPutIPinRC
Log IP addresses in the recentchanges table; can be accessed only by extensions (e....
$wgBlockDisablesLogin
If true, blocked users will not be allowed to login.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfReadOnly()
Check whether the wiki is in read-only mode.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfMemcKey()
Make a cache key for the local wiki.
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition Setup.php:36
$line
Definition cdb.php:59
Deferrable Update for closure/callback updates via IDatabase::doAtomicSection()
bool $mCreateAccount
Definition Block.php:57
int $forcedTargetID
Hack for foreign blocking (CentralAuth)
Definition Block.php:63
static selectFields()
Return the list of ipblocks fields that should be selected to create a new block.
Definition Block.php:193
getPermissionsError(IContextSource $context)
Get the key and parameters for the corresponding error message.
Definition Block.php:1427
bool $isAutoblocking
Definition Block.php:75
insert( $dbw=null)
Insert a block into the block table.
Definition Block.php:462
static getRangeCond( $start, $end=null)
Get a set of SQL conditions which will select rangeblocks encompassing a given range.
Definition Block.php:348
newLoad( $vagueTarget=null)
Load a block from the database which affects the already-set $this->target: 1) A block directly on th...
Definition Block.php:247
update()
Update a block in the DB with new parameters.
Definition Block.php:526
getDatabaseArray( $db=null)
Get an array suitable for passing to $dbw->insert() or $dbw->update()
Definition Block.php:573
prevents( $action, $x=null)
Get/set whether the Block prevents a given action.
Definition Block.php:982
static newFromRow( $row)
Create a new Block object from a database row.
Definition Block.php:426
isHardblock( $x=null)
Get/set whether the Block is a hardblock (affects logged-in users on a given IP/range)
Definition Block.php:952
isValid()
Is the block address valid (i.e.
Definition Block.php:841
User string $target
Definition Block.php:60
bool $isHardblock
Definition Block.php:72
setBlocker( $user)
Set the user who implemented (or will implement) this block.
Definition Block.php:1416
getRedactedName()
Get the block name, but with autoblocked IPs hidden as per standard privacy policy.
Definition Block.php:1017
isExpired()
Has the block expired?
Definition Block.php:826
static newFromID( $id)
Load a blocked user from their block id.
Definition Block.php:173
static getAutoblockExpiry( $timestamp)
Get a timestamp of the expiry for autoblocks.
Definition Block.php:1035
int $mId
Definition Block.php:45
static getBlocksForIPList(array $ipChain, $isAnon, $fromMaster=false)
Get all blocks that match any IP from an array of IP addresses.
Definition Block.php:1122
getRangeEnd()
Get the IP address at the end of the range in Hex form.
Definition Block.php:891
getAutoblockUpdateArray()
Definition Block.php:611
static getIpFragment( $hex)
Get the component of an IP address which is certain to be the same between an IP address and a rangeb...
Definition Block.php:381
static parseTarget( $target)
From an existing Block, get the target and the type of target.
Definition Block.php:1305
bool $mBlockEmail
Definition Block.php:51
static chooseBlock(array $blocks, array $ipChain)
From a list of multiple blocks, find the most exact and strongest Block.
Definition Block.php:1203
bool $mDisableUsertalk
Definition Block.php:54
initFromRow( $row)
Given a database row from the ipblocks table, initialize member variables.
Definition Block.php:395
static isWhitelistedFromAutoblocks( $ip)
Checks whether a given IP is on the autoblock whitelist.
Definition Block.php:692
getId()
Get the block ID.
Definition Block.php:933
getExpiry()
Definition Block.php:1392
getType()
Get the type of target for this particular block.
Definition Block.php:1360
const TYPE_ID
Definition Block.php:82
__construct( $options=[])
Create a new block with specified parameters on a user, IP or IP range.
Definition Block.php:106
getBy()
Get the user id of the blocking sysop.
Definition Block.php:910
setTarget( $target)
Set the target for this block, and update $this->type accordingly.
Definition Block.php:1400
const TYPE_RANGE
Definition Block.php:80
string $mExpiry
Definition Block.php:36
updateTimestamp()
Update the timestamp on autoblocks.
Definition Block.php:848
fromMaster( $x=null)
Get/set a flag determining whether the master is used for reads.
Definition Block.php:943
doAutoblock( $autoblockIP)
Autoblocks the given IP, referring to this Block.
Definition Block.php:738
bool $mHideName
Definition Block.php:39
deleteIfExpired()
Check if a block has expired.
Definition Block.php:808
User $blocker
Definition Block.php:69
doRetroactiveAutoblock()
Retroactively autoblocks the last IP used by the user (if it is a user) blocked by this Block.
Definition Block.php:628
bool $mFromMaster
Definition Block.php:48
int $mParentBlockId
Definition Block.php:42
getTargetAndType()
Get the target and target type for this particular Block.
Definition Block.php:1373
getTarget()
Get the target for this particular Block.
Definition Block.php:1383
const TYPE_USER
Definition Block.php:78
static purgeExpired()
Purge expired blocks from the ipblocks table.
Definition Block.php:1044
getRangeStart()
Get the IP address at the start of the range in Hex form.
Definition Block.php:872
getByName()
Get the username of the blocking sysop.
Definition Block.php:922
equals(Block $block)
Check if two blocks are effectively equal.
Definition Block.php:221
isAutoblocking( $x=null)
Definition Block.php:965
string $mReason
Definition Block.php:27
const TYPE_AUTO
Definition Block.php:81
static defaultRetroactiveAutoblock(Block $block, array &$blockIds)
Retroactively autoblocks the last IP used by the user (if it is a user) blocked by this Block.
Definition Block.php:651
getBlocker()
Get the user who implemented this block.
Definition Block.php:1408
bool $mAuto
Definition Block.php:33
static newFromTarget( $specificTarget, $vagueTarget=null, $fromMaster=false)
Given a target and the target's type, get an existing Block object if possible.
Definition Block.php:1082
int $type
Block::TYPE_ constant.
Definition Block.php:66
string $mTimestamp
Definition Block.php:30
const TYPE_IP
Definition Block.php:79
static isValidBlock( $ipblock)
Validate an IP Block (valid address WITH a valid prefix).
Definition IP.php:126
static isValid( $ip)
Validate an IP address.
Definition IP.php:113
static parseRange( $range)
Given a string range in a number of formats, return the start and end of the range in hexadecimal.
Definition IP.php:501
static sanitizeIP( $ip)
Convert an IP into a verbose, uppercase, normalized form.
Definition IP.php:140
static sanitizeRange( $range)
Gets rid of unneeded numbers in quad-dotted/octet IP strings For example, 127.111....
Definition IP.php:713
static toHex( $ip)
Return a zero-padded upper case hexadecimal representation of an IP address.
Definition IP.php:405
static isInRange( $addr, $range)
Determine if a given IPv4/IPv6 address is in a given CIDR network.
Definition IP.php:638
MediaWiki exception.
MediaWikiServices is the service locator for the application scope of MediaWiki.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:48
getName()
Get the user name, or the IP of an anonymous user.
Definition User.php:2108
isAllowed( $action='')
Internal mechanics of testing a permission.
Definition User.php:3443
getId()
Get the user's ID.
Definition User.php:2083
getUserPage()
Get this user's personal page title.
Definition User.php:4151
$res
Definition database.txt:21
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition deferred.txt:11
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 LIST_OR
Definition Defines.php:38
const LIST_AND
Definition Defines.php:35
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 $status
Definition hooks.txt:1049
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
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition hooks.txt:183
either a plain
Definition hooks.txt:1990
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 as context $options
Definition hooks.txt:1096
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 set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt;div ...>$1&lt;/div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
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 true
Definition hooks.txt:1950
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition hooks.txt:2900
processing should stop and the error should be shown to the user * false
Definition hooks.txt:189
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
Interface for objects which can provide a MediaWiki context on request.
getLanguage()
Get the Language object.
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:34
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
addQuotes( $s)
Adds quotes and backslashes.
delete( $table, $conds, $fname=__METHOD__)
DELETE query wrapper.
$context
Definition load.php:50
$cache
Definition mcc.php:33
This document describes the state of Postgres support in and is fairly well maintained The main code is very well while extensions are very hit and miss it is probably the most supported database after MySQL Much of the work in making MediaWiki database agnostic came about through the work of creating Postgres as and are nearing end of but without copying over all the usage comments General notes on the but these can almost always be programmed around *Although Postgres has a true BOOLEAN type
Definition postgres.txt:36
const DB_REPLICA
Definition defines.php:22
const DB_MASTER
Definition defines.php:23
$lines
Definition router.php:67
if(!isset( $args[0])) $lang
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