MediaWiki master
BlockManager.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Block;
22
23use LogicException;
37use MWCryptHash;
38use Psr\Log\LoggerInterface;
39use Wikimedia\IPSet;
40use Wikimedia\IPUtils;
41
52 public const CONSTRUCTOR_OPTIONS = [
62 ];
63
64 private ServiceOptions $options;
65 private UserFactory $userFactory;
66 private UserIdentityUtils $userIdentityUtils;
67 private LoggerInterface $logger;
68 private HookRunner $hookRunner;
69 private DatabaseBlockStore $blockStore;
70 private ProxyLookup $proxyLookup;
71
72 private BlockCache $userBlockCache;
73 private BlockCache $createAccountBlockCache;
74
75 public function __construct(
76 ServiceOptions $options,
77 UserFactory $userFactory,
78 UserIdentityUtils $userIdentityUtils,
79 LoggerInterface $logger,
80 HookContainer $hookContainer,
81 DatabaseBlockStore $blockStore,
82 ProxyLookup $proxyLookup
83 ) {
84 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
85 $this->options = $options;
86 $this->userFactory = $userFactory;
87 $this->userIdentityUtils = $userIdentityUtils;
88 $this->logger = $logger;
89 $this->hookRunner = new HookRunner( $hookContainer );
90 $this->blockStore = $blockStore;
91 $this->proxyLookup = $proxyLookup;
92
93 $this->userBlockCache = new BlockCache;
94 $this->createAccountBlockCache = new BlockCache;
95 }
96
132 public function getUserBlock(
133 UserIdentity $user,
134 $request,
135 $fromReplica,
136 $disableIpBlockExemptChecking = false
137 ) {
138 // If this is the global user, they may be affected by IP blocks (case #1),
139 // or they may be exempt (case #2). If affected, look for additional blocks
140 // against the IP address and referenced in a cookie.
141 $checkIpBlocks = $request &&
142 // Because calling getBlock within Autopromote leads back to here,
143 // thus causing a infinite recursion. We fix this by not checking for
144 // ipblock-exempt when calling getBlock within Autopromote.
145 // See T270145.
146 !$disableIpBlockExemptChecking &&
147 !$this->isIpBlockExempt( $user );
148
149 return $this->getBlock(
150 $user,
151 $checkIpBlocks ? $request : null,
152 $fromReplica
153 );
154 }
155
173 public function getBlock(
174 UserIdentity $user,
175 ?WebRequest $request,
176 $fromReplica = true
177 ): ?AbstractBlock {
178 $fromPrimary = !$fromReplica;
179 $ip = null;
180
181 // TODO: normalise the fromPrimary parameter when replication is not configured.
182 // Maybe DatabaseBlockStore can tell us about the LoadBalancer configuration.
183 $cacheKey = new BlockCacheKey(
184 $request,
185 $user,
186 $fromPrimary
187 );
188 $block = $this->userBlockCache->get( $cacheKey );
189 if ( $block !== null ) {
190 $this->logger->debug( "Block cache hit with key {$cacheKey}" );
191 return $block ?: null;
192 }
193 $this->logger->debug( "Block cache miss with key {$cacheKey}" );
194
195 if ( $request ) {
196
197 // Case #1: checking the global user, including IP blocks
198 $ip = $request->getIP();
199 // For soft blocks, i.e. blocks that don't block logged-in users,
200 // temporary users are treated as anon users, and are blocked.
201 $applySoftBlocks = !$this->userIdentityUtils->isNamed( $user );
202
203 $xff = $request->getHeader( 'X-Forwarded-For' );
204
205 $blocks = array_merge(
206 $this->blockStore->newListFromTarget( $user, $ip, $fromPrimary ),
207 $this->getSystemIpBlocks( $ip, $applySoftBlocks ),
208 $this->getXffBlocks( $ip, $xff, $applySoftBlocks, $fromPrimary ),
209 $this->getCookieBlock( $user, $request )
210 );
211 } else {
212
213 // Case #2: checking the global user, but they are exempt from IP blocks
214 // and cookie blocks, so we only check for a user account block.
215 // Case #3: checking whether another user's account is blocked.
216 $blocks = $this->blockStore->newListFromTarget( $user, null, $fromPrimary );
217
218 }
219
220 $block = $this->createGetBlockResult( $ip, $blocks );
221
222 $legacyUser = $this->userFactory->newFromUserIdentity( $user );
223 $this->hookRunner->onGetUserBlock( clone $legacyUser, $ip, $block );
224
225 $this->userBlockCache->set( $cacheKey, $block ?: false );
226 return $block;
227 }
228
234 public function clearUserCache( UserIdentity $user ) {
235 $this->userBlockCache->clearUser( $user );
236 $this->createAccountBlockCache->clearUser( $user );
237 }
238
250 public function getCreateAccountBlock(
251 UserIdentity $user,
252 ?WebRequest $request,
253 $fromReplica
254 ) {
255 $key = new BlockCacheKey( $request, $user, $fromReplica );
256 $cachedBlock = $this->createAccountBlockCache->get( $key );
257 if ( $cachedBlock !== null ) {
258 $this->logger->debug( "Create account block cache hit with key {$key}" );
259 return $cachedBlock ?: null;
260 }
261 $this->logger->debug( "Create account block cache miss with key {$key}" );
262
263 $applicableBlocks = [];
264 $userBlock = $this->getBlock( $user, $request, $fromReplica );
265 if ( $userBlock ) {
266 $applicableBlocks = $userBlock->toArray();
267 }
268
269 // T15611: if the IP address the user is trying to create an account from is
270 // blocked with createaccount disabled, prevent new account creation there even
271 // when the user is logged in
272 if ( $request ) {
273 $ipBlock = $this->blockStore->newFromTarget(
274 null, $request->getIP()
275 );
276 if ( $ipBlock ) {
277 $applicableBlocks = array_merge( $applicableBlocks, $ipBlock->toArray() );
278 }
279 }
280
281 foreach ( $applicableBlocks as $i => $block ) {
282 if ( !$block->appliesToRight( 'createaccount' ) ) {
283 unset( $applicableBlocks[$i] );
284 }
285 }
286 $result = $this->createGetBlockResult(
287 $request ? $request->getIP() : null,
288 $applicableBlocks
289 );
290 $this->createAccountBlockCache->set( $key, $result ?: false );
291 return $result;
292 }
293
310 public function filter( ?Block $block, $callback ) {
311 if ( !$block ) {
312 return null;
313 } elseif ( $block instanceof CompositeBlock ) {
314 $blocks = $block->getOriginalBlocks();
315 $originalCount = count( $blocks );
316 foreach ( $blocks as $i => $originalBlock ) {
317 if ( !$callback( $originalBlock ) ) {
318 unset( $blocks[$i] );
319 }
320 }
321 if ( !$blocks ) {
322 return null;
323 } elseif ( count( $blocks ) === 1 ) {
324 return $blocks[ array_key_first( $blocks ) ];
325 } elseif ( count( $blocks ) === $originalCount ) {
326 return $block;
327 } else {
328 return $block->withOriginalBlocks( array_values( $blocks ) );
329 }
330 } elseif ( !$callback( $block ) ) {
331 return null;
332 } else {
333 return $block;
334 }
335 }
336
342 private function isIpBlockExempt( UserIdentity $user ) {
343 return MediaWikiServices::getInstance()->getPermissionManager()
344 ->userHasRight( $user, 'ipblock-exempt' );
345 }
346
352 private function createGetBlockResult( ?string $ip, array $blocks ): ?AbstractBlock {
353 // Filter out any duplicated blocks, e.g. from the cookie
354 $blocks = $this->getUniqueBlocks( $blocks );
355
356 if ( count( $blocks ) === 0 ) {
357 return null;
358 } elseif ( count( $blocks ) === 1 ) {
359 return $blocks[ 0 ];
360 } else {
361 $compositeBlock = CompositeBlock::createFromBlocks( ...$blocks );
362 $compositeBlock->setTarget( $ip );
363 return $compositeBlock;
364 }
365 }
366
376 public function getIpBlock( string $ip, bool $fromReplica ): ?AbstractBlock {
377 if ( !IPUtils::isValid( $ip ) ) {
378 return null;
379 }
380
381 $blocks = array_merge(
382 $this->blockStore->newListFromTarget( $ip, $ip, !$fromReplica ),
383 $this->getSystemIpBlocks( $ip, true )
384 );
385
386 return $this->createGetBlockResult( $ip, $blocks );
387 }
388
396 private function getCookieBlock( UserIdentity $user, WebRequest $request ): array {
397 $cookieBlock = $this->getBlockFromCookieValue( $user, $request );
398
399 return $cookieBlock instanceof DatabaseBlock ? [ $cookieBlock ] : [];
400 }
401
409 private function getSystemIpBlocks( string $ip, bool $applySoftBlocks ): array {
410 $blocks = [];
411
412 // Proxy blocking
413 if ( !in_array( $ip, $this->options->get( MainConfigNames::ProxyWhitelist ) ) ) {
414 // Local list
415 if ( $this->isLocallyBlockedProxy( $ip ) ) {
416 $blocks[] = new SystemBlock( [
417 'reason' => new Message( 'proxyblockreason' ),
418 'address' => $ip,
419 'systemBlock' => 'proxy',
420 ] );
421 } elseif ( $applySoftBlocks && $this->isDnsBlacklisted( $ip ) ) {
422 $blocks[] = new SystemBlock( [
423 'reason' => new Message( 'sorbsreason' ),
424 'address' => $ip,
425 'anonOnly' => true,
426 'systemBlock' => 'dnsbl',
427 ] );
428 }
429 }
430
431 // Soft blocking
432 if ( $applySoftBlocks && IPUtils::isInRanges( $ip, $this->options->get( MainConfigNames::SoftBlockRanges ) ) ) {
433 $blocks[] = new SystemBlock( [
434 'address' => $ip,
435 'reason' => new Message( 'softblockrangesreason', [ $ip ] ),
436 'anonOnly' => true,
437 'systemBlock' => 'wgSoftBlockRanges',
438 ] );
439 }
440
441 return $blocks;
442 }
443
455 private function getXffBlocks(
456 string $ip,
457 string $xff,
458 bool $applySoftBlocks,
459 bool $fromPrimary
460 ): array {
461 // (T25343) Apply IP blocks to the contents of XFF headers, if enabled
462 if ( $this->options->get( MainConfigNames::ApplyIpBlocksToXff )
463 && !in_array( $ip, $this->options->get( MainConfigNames::ProxyWhitelist ) )
464 ) {
465 $xff = array_map( 'trim', explode( ',', $xff ) );
466 $xff = array_diff( $xff, [ $ip ] );
467 $xffblocks = $this->getBlocksForIPList( $xff, $applySoftBlocks, $fromPrimary );
468
469 // (T285159) Exclude autoblocks from XFF headers to prevent spoofed
470 // headers uncovering the IPs of autoblocked users
471 $xffblocks = array_filter( $xffblocks, static function ( $block ) {
472 return $block->getType() !== Block::TYPE_AUTO;
473 } );
474
475 return $xffblocks;
476 }
477
478 return [];
479 }
480
493 public function getBlocksForIPList( array $ipChain, bool $applySoftBlocks, bool $fromPrimary ) {
494 if ( $ipChain === [] ) {
495 return [];
496 }
497
498 $ips = [];
499 foreach ( array_unique( $ipChain ) as $ipaddr ) {
500 // Discard invalid IP addresses. Since XFF can be spoofed and we do not
501 // necessarily trust the header given to us, make sure that we are only
502 // checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
503 // Do not treat private IP spaces as special as it may be desirable for wikis
504 // to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
505 if ( !IPUtils::isValid( $ipaddr ) ) {
506 continue;
507 }
508 // Don't check trusted IPs (includes local CDNs which will be in every request)
509 if ( $this->proxyLookup->isTrustedProxy( $ipaddr ) ) {
510 continue;
511 }
512 $ips[] = $ipaddr;
513 }
514 return $this->blockStore->newListFromIPs( $ips, $applySoftBlocks, $fromPrimary );
515 }
516
527 private function getUniqueBlocks( array $blocks ) {
528 $systemBlocks = [];
529 $databaseBlocks = [];
530
531 foreach ( $blocks as $block ) {
532 if ( $block instanceof SystemBlock ) {
533 $systemBlocks[] = $block;
534 } elseif ( $block->getType() === DatabaseBlock::TYPE_AUTO && $block instanceof DatabaseBlock ) {
535 if ( !isset( $databaseBlocks[$block->getParentBlockId()] ) ) {
536 $databaseBlocks[$block->getParentBlockId()] = $block;
537 }
538 } else {
539 // @phan-suppress-next-line PhanTypeMismatchDimAssignment getId is not null here
540 $databaseBlocks[$block->getId()] = $block;
541 }
542 }
543
544 return array_values( array_merge( $systemBlocks, $databaseBlocks ) );
545 }
546
558 private function getBlockFromCookieValue(
559 UserIdentity $user,
560 WebRequest $request
561 ) {
562 $cookieValue = $request->getCookie( 'BlockID' );
563 if ( $cookieValue === null ) {
564 return false;
565 }
566
567 $blockCookieId = $this->getIdFromCookieValue( $cookieValue );
568 if ( $blockCookieId !== null ) {
569 $block = $this->blockStore->newFromID( $blockCookieId );
570 if (
571 $block instanceof DatabaseBlock &&
572 $this->shouldApplyCookieBlock( $block, !$user->isRegistered() )
573 ) {
574 return $block;
575 }
576 }
577
578 return false;
579 }
580
588 private function shouldApplyCookieBlock( DatabaseBlock $block, $isAnon ) {
589 if ( !$block->isExpired() ) {
590 switch ( $block->getType() ) {
591 case DatabaseBlock::TYPE_IP:
592 case DatabaseBlock::TYPE_RANGE:
593 // If block is type IP or IP range, load only
594 // if user is not logged in (T152462)
595 return $isAnon &&
596 $this->options->get( MainConfigNames::CookieSetOnIpBlock );
597 case DatabaseBlock::TYPE_USER:
598 return $block->isAutoblocking() &&
599 $this->options->get( MainConfigNames::CookieSetOnAutoblock );
600 default:
601 return false;
602 }
603 }
604 return false;
605 }
606
613 private function isLocallyBlockedProxy( $ip ) {
614 $proxyList = $this->options->get( MainConfigNames::ProxyList );
615 if ( !$proxyList ) {
616 return false;
617 }
618
619 if ( !is_array( $proxyList ) ) {
620 // Load values from the specified file
621 $proxyList = array_map( 'trim', file( $proxyList ) );
622 }
623
624 $proxyListIPSet = new IPSet( $proxyList );
625 return $proxyListIPSet->match( $ip );
626 }
627
635 public function isDnsBlacklisted( $ip, $checkAllowed = false ) {
636 if ( !$this->options->get( MainConfigNames::EnableDnsBlacklist ) ||
637 ( $checkAllowed && in_array( $ip, $this->options->get( MainConfigNames::ProxyWhitelist ) ) )
638 ) {
639 return false;
640 }
641
642 return $this->inDnsBlacklist( $ip, $this->options->get( MainConfigNames::DnsBlacklistUrls ) );
643 }
644
652 private function inDnsBlacklist( $ip, array $bases ) {
653 $found = false;
654 // @todo FIXME: IPv6 ??? (https://bugs.php.net/bug.php?id=33170)
655 if ( IPUtils::isIPv4( $ip ) ) {
656 // Reverse IP, T23255
657 $ipReversed = implode( '.', array_reverse( explode( '.', $ip ) ) );
658
659 foreach ( $bases as $base ) {
660 // Make hostname
661 // If we have an access key, use that too (ProjectHoneypot, etc.)
662 $basename = $base;
663 if ( is_array( $base ) ) {
664 if ( count( $base ) >= 2 ) {
665 // Access key is 1, base URL is 0
666 $hostname = "{$base[1]}.$ipReversed.{$base[0]}";
667 } else {
668 $hostname = "$ipReversed.{$base[0]}";
669 }
670 $basename = $base[0];
671 } else {
672 $hostname = "$ipReversed.$base";
673 }
674
675 // Send query
676 $ipList = $this->checkHost( $hostname );
677
678 if ( $ipList ) {
679 $this->logger->info(
680 'Hostname {hostname} is {ipList}, it\'s a proxy says {basename}!',
681 [
682 'hostname' => $hostname,
683 'ipList' => $ipList[0],
684 'basename' => $basename,
685 ]
686 );
687 $found = true;
688 break;
689 }
690
691 $this->logger->debug( "Requested $hostname, not found in $basename." );
692 }
693 }
694
695 return $found;
696 }
697
704 protected function checkHost( $hostname ) {
705 return gethostbynamel( $hostname );
706 }
707
727 public function trackBlockWithCookie( User $user, WebResponse $response ) {
728 if ( !$this->options->get( MainConfigNames::CookieSetOnIpBlock ) &&
729 !$this->options->get( MainConfigNames::CookieSetOnAutoblock ) ) {
730 // Cookie blocks are disabled, return early to prevent executing unnecessary logic.
731 return;
732 }
733
734 $request = $user->getRequest();
735
736 if ( $request->getCookie( 'BlockID' ) !== null ) {
737 $cookieBlock = $this->getBlockFromCookieValue( $user, $request );
738 if ( $cookieBlock && $this->shouldApplyCookieBlock( $cookieBlock, $user->isAnon() ) ) {
739 return;
740 }
741 // The block pointed to by the cookie is invalid or should not be tracked.
742 $this->clearBlockCookie( $response );
743 }
744
745 if ( !$user->isSafeToLoad() ) {
746 // Prevent a circular dependency by not allowing this method to be called
747 // before or while the user is being loaded.
748 // E.g. User > BlockManager > Block > Message > getLanguage > User.
749 // See also T180050 and T226777.
750 throw new LogicException( __METHOD__ . ' requires a loaded User object' );
751 }
752 if ( $response->headersSent() ) {
753 throw new LogicException( __METHOD__ . ' must be called pre-send' );
754 }
755
756 $block = $user->getBlock();
757 $isAnon = $user->isAnon();
758
759 if ( $block ) {
760 foreach ( $block->toArray() as $originalBlock ) {
761 // TODO: Improve on simply tracking the first trackable block (T225654)
762 if ( $originalBlock instanceof DatabaseBlock
763 && $this->shouldTrackBlockWithCookie( $originalBlock, $isAnon )
764 ) {
765 $this->setBlockCookie( $originalBlock, $response );
766 return;
767 }
768 }
769 }
770 }
771
780 private function setBlockCookie( DatabaseBlock $block, WebResponse $response ) {
781 // Calculate the default expiry time.
782 $maxExpiryTime = wfTimestamp( TS_MW, (int)wfTimestamp() + ( 24 * 60 * 60 ) );
783
784 // Use the block's expiry time only if it's less than the default.
785 $expiryTime = $block->getExpiry();
786 if ( $expiryTime === 'infinity' || $expiryTime > $maxExpiryTime ) {
787 $expiryTime = $maxExpiryTime;
788 }
789
790 // Set the cookie
791 $expiryValue = (int)wfTimestamp( TS_UNIX, $expiryTime );
792 $cookieOptions = [ 'httpOnly' => false ];
793 $cookieValue = $this->getCookieValue( $block );
794 $response->setCookie( 'BlockID', $cookieValue, $expiryValue, $cookieOptions );
795 }
796
804 private function shouldTrackBlockWithCookie( DatabaseBlock $block, $isAnon ) {
805 switch ( $block->getType() ) {
806 case DatabaseBlock::TYPE_IP:
807 case DatabaseBlock::TYPE_RANGE:
808 return $isAnon && $this->options->get( MainConfigNames::CookieSetOnIpBlock );
809 case DatabaseBlock::TYPE_USER:
810 return !$isAnon &&
811 $this->options->get( MainConfigNames::CookieSetOnAutoblock ) &&
812 $block->isAutoblocking();
813 default:
814 return false;
815 }
816 }
817
824 public static function clearBlockCookie( WebResponse $response ) {
825 $response->clearCookie( 'BlockID', [ 'httpOnly' => false ] );
826 }
827
836 private function getIdFromCookieValue( $cookieValue ) {
837 // The cookie value must start with a number
838 if ( !is_numeric( substr( $cookieValue, 0, 1 ) ) ) {
839 return null;
840 }
841
842 // Extract the ID prefix from the cookie value (may be the whole value, if no bang found).
843 $bangPos = strpos( $cookieValue, '!' );
844 $id = ( $bangPos === false ) ? $cookieValue : substr( $cookieValue, 0, $bangPos );
845 if ( !$this->options->get( MainConfigNames::SecretKey ) ) {
846 // If there's no secret key, just use the ID as given.
847 return (int)$id;
848 }
849 $storedHmac = substr( $cookieValue, $bangPos + 1 );
850 $calculatedHmac = MWCryptHash::hmac( $id, $this->options->get( MainConfigNames::SecretKey ), false );
851 if ( $calculatedHmac === $storedHmac ) {
852 return (int)$id;
853 } else {
854 return null;
855 }
856 }
857
867 private function getCookieValue( DatabaseBlock $block ) {
868 $id = (string)$block->getId();
869 if ( !$this->options->get( MainConfigNames::SecretKey ) ) {
870 // If there's no secret key, don't append a HMAC.
871 return $id;
872 }
873 $hmac = MWCryptHash::hmac( $id, $this->options->get( MainConfigNames::SecretKey ), false );
874 return $id . '!' . $hmac;
875 }
876}
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
static hmac( $data, $key, $raw=true)
Generate a keyed cryptographic hash value (HMAC) for a string, making use of the best hash algorithm ...
getExpiry()
Get the block expiry time.
A service class for checking blocks.
trackBlockWithCookie(User $user, WebResponse $response)
Set the 'BlockID' cookie depending on block type and user authentication status.
isDnsBlacklisted( $ip, $checkAllowed=false)
Whether the given IP is in a DNS blacklist.
getIpBlock(string $ip, bool $fromReplica)
Get the blocks that apply to an IP address.
__construct(ServiceOptions $options, UserFactory $userFactory, UserIdentityUtils $userIdentityUtils, LoggerInterface $logger, HookContainer $hookContainer, DatabaseBlockStore $blockStore, ProxyLookup $proxyLookup)
clearUserCache(UserIdentity $user)
Clear the cache of any blocks that refer to the specified user.
filter(?Block $block, $callback)
Remove elements of a block which fail a callback test.
checkHost( $hostname)
Wrapper for mocking in tests.
getBlocksForIPList(array $ipChain, bool $applySoftBlocks, bool $fromPrimary)
Get all blocks that match any IP from an array of IP addresses.
getCreateAccountBlock(UserIdentity $user, ?WebRequest $request, $fromReplica)
Get the block which applies to a create account action, if there is any.
getUserBlock(UserIdentity $user, $request, $fromReplica, $disableIpBlockExemptChecking=false)
Get the blocks that apply to a user.
static clearBlockCookie(WebResponse $response)
Unset the 'BlockID' cookie.
getBlock(UserIdentity $user, ?WebRequest $request, $fromReplica=true)
Get the blocks that apply to a user.
static createFromBlocks(AbstractBlock ... $blocks)
Helper method for merging multiple blocks into a composite block.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
System blocks are temporary blocks that are created on enforcement (e.g.
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
A class containing constants representing the names of configuration variables.
const DnsBlacklistUrls
Name constant for the DnsBlacklistUrls setting, for use with Config::get()
const SoftBlockRanges
Name constant for the SoftBlockRanges setting, for use with Config::get()
const CookieSetOnAutoblock
Name constant for the CookieSetOnAutoblock setting, for use with Config::get()
const EnableDnsBlacklist
Name constant for the EnableDnsBlacklist setting, for use with Config::get()
const ApplyIpBlocksToXff
Name constant for the ApplyIpBlocksToXff setting, for use with Config::get()
const ProxyList
Name constant for the ProxyList setting, for use with Config::get()
const ProxyWhitelist
Name constant for the ProxyWhitelist setting, for use with Config::get()
const CookieSetOnIpBlock
Name constant for the CookieSetOnIpBlock setting, for use with Config::get()
const SecretKey
Name constant for the SecretKey setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:155
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...
getHeader( $name, $flags=0)
Get a request header, or false if it isn't set.
getIP()
Work out the IP address based on various globals For trusted proxies, use the XFF client IP (first of...
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
headersSent()
Test if headers have been sent.
setCookie( $name, $value, $expire=0, $options=[])
Set the browser cookie.
clearCookie( $name, $options=[])
Unset a browser cookie.
Creates User objects.
Convenience functions for interpreting UserIdentity objects using additional services or config.
internal since 1.36
Definition User.php:93
isSafeToLoad()
Test if it's safe to load this User object.
Definition User.php:331
getBlock( $freshness=IDBAccessObject::READ_NORMAL, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
Definition User.php:1418
isAnon()
Get whether the user is anonymous.
Definition User.php:2122
getRequest()
Get the WebRequest object to use with this object.
Definition User.php:2220
Represents a block that may prevent users from performing specific operations.
Definition Block.php:45
Interface for objects representing user identity.