MediaWiki REL1_28
IP.php
Go to the documentation of this file.
1<?php
24use IPSet\IPSet;
25
26// Some regex definition to "play" with IP address and IP address blocks
27
28// An IPv4 address is made of 4 bytes from x00 to xFF which is d0 to d255
29define( 'RE_IP_BYTE', '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])' );
30define( 'RE_IP_ADD', RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.' . RE_IP_BYTE );
31// An IPv4 block is an IP address and a prefix (d1 to d32)
32define( 'RE_IP_PREFIX', '(3[0-2]|[12]?\d)' );
33define( 'RE_IP_BLOCK', RE_IP_ADD . '\/' . RE_IP_PREFIX );
34
35// An IPv6 address is made up of 8 words (each x0000 to xFFFF).
36// However, the "::" abbreviation can be used on consecutive x0000 words.
37define( 'RE_IPV6_WORD', '([0-9A-Fa-f]{1,4})' );
38define( 'RE_IPV6_PREFIX', '(12[0-8]|1[01][0-9]|[1-9]?\d)' );
39define( 'RE_IPV6_ADD',
40 '(?:' . // starts with "::" (including "::")
41 ':(?::|(?::' . RE_IPV6_WORD . '){1,7})' .
42 '|' . // ends with "::" (except "::")
43 RE_IPV6_WORD . '(?::' . RE_IPV6_WORD . '){0,6}::' .
44 '|' . // contains one "::" in the middle (the ^ makes the test fail if none found)
45 RE_IPV6_WORD . '(?::((?(-1)|:))?' . RE_IPV6_WORD . '){1,6}(?(-2)|^)' .
46 '|' . // contains no "::"
47 RE_IPV6_WORD . '(?::' . RE_IPV6_WORD . '){7}' .
48 ')'
49);
50// An IPv6 block is an IP address and a prefix (d1 to d128)
51define( 'RE_IPV6_BLOCK', RE_IPV6_ADD . '\/' . RE_IPV6_PREFIX );
52// For IPv6 canonicalization (NOT for strict validation; these are quite lax!)
53define( 'RE_IPV6_GAP', ':(?:0+:)*(?::(?:0+:)*)?' );
54define( 'RE_IPV6_V4_PREFIX', '0*' . RE_IPV6_GAP . '(?:ffff:)?' );
55
56// This might be useful for regexps used elsewhere, matches any IPv4 or IPv6 address or network
57define( 'IP_ADDRESS_STRING',
58 '(?:' .
59 RE_IP_ADD . '(?:\/' . RE_IP_PREFIX . ')?' . // IPv4
60 '|' .
61 RE_IPV6_ADD . '(?:\/' . RE_IPV6_PREFIX . ')?' . // IPv6
62 ')'
63);
64
69class IP {
71 private static $proxyIpSet = null;
72
81 public static function isIPAddress( $ip ) {
82 return (bool)preg_match( '/^' . IP_ADDRESS_STRING . '$/', $ip );
83 }
84
92 public static function isIPv6( $ip ) {
93 return (bool)preg_match( '/^' . RE_IPV6_ADD . '(?:\/' . RE_IPV6_PREFIX . ')?$/', $ip );
94 }
95
103 public static function isIPv4( $ip ) {
104 return (bool)preg_match( '/^' . RE_IP_ADD . '(?:\/' . RE_IP_PREFIX . ')?$/', $ip );
105 }
106
115 public static function isValid( $ip ) {
116 return ( preg_match( '/^' . RE_IP_ADD . '$/', $ip )
117 || preg_match( '/^' . RE_IPV6_ADD . '$/', $ip ) );
118 }
119
128 public static function isValidBlock( $ipblock ) {
129 return ( preg_match( '/^' . RE_IPV6_BLOCK . '$/', $ipblock )
130 || preg_match( '/^' . RE_IP_BLOCK . '$/', $ipblock ) );
131 }
132
142 public static function sanitizeIP( $ip ) {
143 $ip = trim( $ip );
144 if ( $ip === '' ) {
145 return null;
146 }
147 /* If not an IP, just return trimmed value, since sanitizeIP() is called
148 * in a number of contexts where usernames are supplied as input.
149 */
150 if ( !self::isIPAddress( $ip ) ) {
151 return $ip;
152 }
153 if ( self::isIPv4( $ip ) ) {
154 // Remove leading 0's from octet representation of IPv4 address
155 $ip = preg_replace( '/(?:^|(?<=\.))0+(?=[1-9]|0\.|0$)/', '', $ip );
156 return $ip;
157 }
158 // Remove any whitespaces, convert to upper case
159 $ip = strtoupper( $ip );
160 // Expand zero abbreviations
161 $abbrevPos = strpos( $ip, '::' );
162 if ( $abbrevPos !== false ) {
163 // We know this is valid IPv6. Find the last index of the
164 // address before any CIDR number (e.g. "a:b:c::/24").
165 $CIDRStart = strpos( $ip, "/" );
166 $addressEnd = ( $CIDRStart !== false )
167 ? $CIDRStart - 1
168 : strlen( $ip ) - 1;
169 // If the '::' is at the beginning...
170 if ( $abbrevPos == 0 ) {
171 $repeat = '0:';
172 $extra = ( $ip == '::' ) ? '0' : ''; // for the address '::'
173 $pad = 9; // 7+2 (due to '::')
174 // If the '::' is at the end...
175 } elseif ( $abbrevPos == ( $addressEnd - 1 ) ) {
176 $repeat = ':0';
177 $extra = '';
178 $pad = 9; // 7+2 (due to '::')
179 // If the '::' is in the middle...
180 } else {
181 $repeat = ':0';
182 $extra = ':';
183 $pad = 8; // 6+2 (due to '::')
184 }
185 $ip = str_replace( '::',
186 str_repeat( $repeat, $pad - substr_count( $ip, ':' ) ) . $extra,
187 $ip
188 );
189 }
190 // Remove leading zeros from each bloc as needed
191 $ip = preg_replace( '/(^|:)0+(' . RE_IPV6_WORD . ')/', '$1$2', $ip );
192
193 return $ip;
194 }
195
203 public static function prettifyIP( $ip ) {
204 $ip = self::sanitizeIP( $ip ); // normalize (removes '::')
205 if ( self::isIPv6( $ip ) ) {
206 // Split IP into an address and a CIDR
207 if ( strpos( $ip, '/' ) !== false ) {
208 list( $ip, $cidr ) = explode( '/', $ip, 2 );
209 } else {
210 list( $ip, $cidr ) = [ $ip, '' ];
211 }
212 // Get the largest slice of words with multiple zeros
213 $offset = 0;
214 $longest = $longestPos = false;
215 while ( preg_match(
216 '!(?:^|:)0(?::0)+(?:$|:)!', $ip, $m, PREG_OFFSET_CAPTURE, $offset
217 ) ) {
218 list( $match, $pos ) = $m[0]; // full match
219 if ( strlen( $match ) > strlen( $longest ) ) {
220 $longest = $match;
221 $longestPos = $pos;
222 }
223 $offset = ( $pos + strlen( $match ) ); // advance
224 }
225 if ( $longest !== false ) {
226 // Replace this portion of the string with the '::' abbreviation
227 $ip = substr_replace( $ip, '::', $longestPos, strlen( $longest ) );
228 }
229 // Add any CIDR back on
230 if ( $cidr !== '' ) {
231 $ip = "{$ip}/{$cidr}";
232 }
233 // Convert to lower case to make it more readable
234 $ip = strtolower( $ip );
235 }
236
237 return $ip;
238 }
239
256 public static function splitHostAndPort( $both ) {
257 if ( substr( $both, 0, 1 ) === '[' ) {
258 if ( preg_match( '/^\[(' . RE_IPV6_ADD . ')\](?::(?P<port>\d+))?$/', $both, $m ) ) {
259 if ( isset( $m['port'] ) ) {
260 return [ $m[1], intval( $m['port'] ) ];
261 } else {
262 return [ $m[1], false ];
263 }
264 } else {
265 // Square bracket found but no IPv6
266 return false;
267 }
268 }
269 $numColons = substr_count( $both, ':' );
270 if ( $numColons >= 2 ) {
271 // Is it a bare IPv6 address?
272 if ( preg_match( '/^' . RE_IPV6_ADD . '$/', $both ) ) {
273 return [ $both, false ];
274 } else {
275 // Not valid IPv6, but too many colons for anything else
276 return false;
277 }
278 }
279 if ( $numColons >= 1 ) {
280 // Host:port?
281 $bits = explode( ':', $both );
282 if ( preg_match( '/^\d+/', $bits[1] ) ) {
283 return [ $bits[0], intval( $bits[1] ) ];
284 } else {
285 // Not a valid port
286 return false;
287 }
288 }
289
290 // Plain hostname
291 return [ $both, false ];
292 }
293
305 public static function combineHostAndPort( $host, $port, $defaultPort = false ) {
306 if ( strpos( $host, ':' ) !== false ) {
307 $host = "[$host]";
308 }
309 if ( $defaultPort !== false && $port == $defaultPort ) {
310 return $host;
311 } else {
312 return "$host:$port";
313 }
314 }
315
322 public static function formatHex( $hex ) {
323 if ( substr( $hex, 0, 3 ) == 'v6-' ) { // IPv6
324 return self::hexToOctet( substr( $hex, 3 ) );
325 } else { // IPv4
326 return self::hexToQuad( $hex );
327 }
328 }
329
336 public static function hexToOctet( $ip_hex ) {
337 // Pad hex to 32 chars (128 bits)
338 $ip_hex = str_pad( strtoupper( $ip_hex ), 32, '0', STR_PAD_LEFT );
339 // Separate into 8 words
340 $ip_oct = substr( $ip_hex, 0, 4 );
341 for ( $n = 1; $n < 8; $n++ ) {
342 $ip_oct .= ':' . substr( $ip_hex, 4 * $n, 4 );
343 }
344 // NO leading zeroes
345 $ip_oct = preg_replace( '/(^|:)0+(' . RE_IPV6_WORD . ')/', '$1$2', $ip_oct );
346
347 return $ip_oct;
348 }
349
356 public static function hexToQuad( $ip_hex ) {
357 // Pad hex to 8 chars (32 bits)
358 $ip_hex = str_pad( strtoupper( $ip_hex ), 8, '0', STR_PAD_LEFT );
359 // Separate into four quads
360 $s = '';
361 for ( $i = 0; $i < 4; $i++ ) {
362 if ( $s !== '' ) {
363 $s .= '.';
364 }
365 $s .= base_convert( substr( $ip_hex, $i * 2, 2 ), 16, 10 );
366 }
367
368 return $s;
369 }
370
378 public static function isPublic( $ip ) {
379 static $privateSet = null;
380 if ( !$privateSet ) {
381 $privateSet = new IPSet( [
382 '10.0.0.0/8', # RFC 1918 (private)
383 '172.16.0.0/12', # RFC 1918 (private)
384 '192.168.0.0/16', # RFC 1918 (private)
385 '0.0.0.0/8', # this network
386 '127.0.0.0/8', # loopback
387 'fc00::/7', # RFC 4193 (local)
388 '0:0:0:0:0:0:0:1', # loopback
389 '169.254.0.0/16', # link-local
390 'fe80::/10', # link-local
391 ] );
392 }
393 return !$privateSet->match( $ip );
394 }
395
407 public static function toHex( $ip ) {
408 if ( self::isIPv6( $ip ) ) {
409 $n = 'v6-' . self::IPv6ToRawHex( $ip );
410 } elseif ( self::isIPv4( $ip ) ) {
411 // T62035/T97897: An IP with leading 0's fails in ip2long sometimes (e.g. *.08),
412 // also double/triple 0 needs to be changed to just a single 0 for ip2long.
413 $ip = self::sanitizeIP( $ip );
414 $n = ip2long( $ip );
415 if ( $n < 0 ) {
416 $n += pow( 2, 32 );
417 # On 32-bit platforms (and on Windows), 2^32 does not fit into an int,
418 # so $n becomes a float. We convert it to string instead.
419 if ( is_float( $n ) ) {
420 $n = (string)$n;
421 }
422 }
423 if ( $n !== false ) {
424 # Floating points can handle the conversion; faster than Wikimedia\base_convert()
425 $n = strtoupper( str_pad( base_convert( $n, 10, 16 ), 8, '0', STR_PAD_LEFT ) );
426 }
427 } else {
428 $n = false;
429 }
430
431 return $n;
432 }
433
440 private static function IPv6ToRawHex( $ip ) {
441 $ip = self::sanitizeIP( $ip );
442 if ( !$ip ) {
443 return false;
444 }
445 $r_ip = '';
446 foreach ( explode( ':', $ip ) as $v ) {
447 $r_ip .= str_pad( $v, 4, 0, STR_PAD_LEFT );
448 }
449
450 return $r_ip;
451 }
452
460 public static function parseCIDR( $range ) {
461 if ( self::isIPv6( $range ) ) {
462 return self::parseCIDR6( $range );
463 }
464 $parts = explode( '/', $range, 2 );
465 if ( count( $parts ) != 2 ) {
466 return [ false, false ];
467 }
468 list( $network, $bits ) = $parts;
469 $network = ip2long( $network );
470 if ( $network !== false && is_numeric( $bits ) && $bits >= 0 && $bits <= 32 ) {
471 if ( $bits == 0 ) {
472 $network = 0;
473 } else {
474 $network &= ~( ( 1 << ( 32 - $bits ) ) - 1 );
475 }
476 # Convert to unsigned
477 if ( $network < 0 ) {
478 $network += pow( 2, 32 );
479 }
480 } else {
481 $network = false;
482 $bits = false;
483 }
484
485 return [ $network, $bits ];
486 }
487
503 public static function parseRange( $range ) {
504 // CIDR notation
505 if ( strpos( $range, '/' ) !== false ) {
506 if ( self::isIPv6( $range ) ) {
507 return self::parseRange6( $range );
508 }
509 list( $network, $bits ) = self::parseCIDR( $range );
510 if ( $network === false ) {
511 $start = $end = false;
512 } else {
513 $start = sprintf( '%08X', $network );
514 $end = sprintf( '%08X', $network + pow( 2, ( 32 - $bits ) ) - 1 );
515 }
516 // Explicit range
517 } elseif ( strpos( $range, '-' ) !== false ) {
518 list( $start, $end ) = array_map( 'trim', explode( '-', $range, 2 ) );
519 if ( self::isIPv6( $start ) && self::isIPv6( $end ) ) {
520 return self::parseRange6( $range );
521 }
522 if ( self::isIPv4( $start ) && self::isIPv4( $end ) ) {
523 $start = self::toHex( $start );
524 $end = self::toHex( $end );
525 if ( $start > $end ) {
526 $start = $end = false;
527 }
528 } else {
529 $start = $end = false;
530 }
531 } else {
532 # Single IP
533 $start = $end = self::toHex( $range );
534 }
535 if ( $start === false || $end === false ) {
536 return [ false, false ];
537 } else {
538 return [ $start, $end ];
539 }
540 }
541
550 private static function parseCIDR6( $range ) {
551 # Explode into <expanded IP,range>
552 $parts = explode( '/', IP::sanitizeIP( $range ), 2 );
553 if ( count( $parts ) != 2 ) {
554 return [ false, false ];
555 }
556 list( $network, $bits ) = $parts;
557 $network = self::IPv6ToRawHex( $network );
558 if ( $network !== false && is_numeric( $bits ) && $bits >= 0 && $bits <= 128 ) {
559 if ( $bits == 0 ) {
560 $network = "0";
561 } else {
562 # Native 32 bit functions WONT work here!!!
563 # Convert to a padded binary number
564 $network = Wikimedia\base_convert( $network, 16, 2, 128 );
565 # Truncate the last (128-$bits) bits and replace them with zeros
566 $network = str_pad( substr( $network, 0, $bits ), 128, 0, STR_PAD_RIGHT );
567 # Convert back to an integer
568 $network = Wikimedia\base_convert( $network, 2, 10 );
569 }
570 } else {
571 $network = false;
572 $bits = false;
573 }
574
575 return [ $network, (int)$bits ];
576 }
577
591 private static function parseRange6( $range ) {
592 # Expand any IPv6 IP
593 $range = IP::sanitizeIP( $range );
594 // CIDR notation...
595 if ( strpos( $range, '/' ) !== false ) {
596 list( $network, $bits ) = self::parseCIDR6( $range );
597 if ( $network === false ) {
598 $start = $end = false;
599 } else {
600 $start = Wikimedia\base_convert( $network, 10, 16, 32, false );
601 # Turn network to binary (again)
602 $end = Wikimedia\base_convert( $network, 10, 2, 128 );
603 # Truncate the last (128-$bits) bits and replace them with ones
604 $end = str_pad( substr( $end, 0, $bits ), 128, 1, STR_PAD_RIGHT );
605 # Convert to hex
606 $end = Wikimedia\base_convert( $end, 2, 16, 32, false );
607 # see toHex() comment
608 $start = "v6-$start";
609 $end = "v6-$end";
610 }
611 // Explicit range notation...
612 } elseif ( strpos( $range, '-' ) !== false ) {
613 list( $start, $end ) = array_map( 'trim', explode( '-', $range, 2 ) );
614 $start = self::toHex( $start );
615 $end = self::toHex( $end );
616 if ( $start > $end ) {
617 $start = $end = false;
618 }
619 } else {
620 # Single IP
621 $start = $end = self::toHex( $range );
622 }
623 if ( $start === false || $end === false ) {
624 return [ false, false ];
625 } else {
626 return [ $start, $end ];
627 }
628 }
629
640 public static function isInRange( $addr, $range ) {
641 $hexIP = self::toHex( $addr );
642 list( $start, $end ) = self::parseRange( $range );
643
644 return ( strcmp( $hexIP, $start ) >= 0 &&
645 strcmp( $hexIP, $end ) <= 0 );
646 }
647
658 public static function isInRanges( $ip, $ranges ) {
659 foreach ( $ranges as $range ) {
660 if ( self::isInRange( $ip, $range ) ) {
661 return true;
662 }
663 }
664 return false;
665 }
666
677 public static function canonicalize( $addr ) {
678 // remove zone info (bug 35738)
679 $addr = preg_replace( '/\%.*/', '', $addr );
680
681 if ( self::isValid( $addr ) ) {
682 return $addr;
683 }
684 // Turn mapped addresses from ::ce:ffff:1.2.3.4 to 1.2.3.4
685 if ( strpos( $addr, ':' ) !== false && strpos( $addr, '.' ) !== false ) {
686 $addr = substr( $addr, strrpos( $addr, ':' ) + 1 );
687 if ( self::isIPv4( $addr ) ) {
688 return $addr;
689 }
690 }
691 // IPv6 loopback address
692 $m = [];
693 if ( preg_match( '/^0*' . RE_IPV6_GAP . '1$/', $addr, $m ) ) {
694 return '127.0.0.1';
695 }
696 // IPv4-mapped and IPv4-compatible IPv6 addresses
697 if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . '(' . RE_IP_ADD . ')$/i', $addr, $m ) ) {
698 return $m[1];
699 }
700 if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . RE_IPV6_WORD .
701 ':' . RE_IPV6_WORD . '$/i', $addr, $m )
702 ) {
703 return long2ip( ( hexdec( $m[1] ) << 16 ) + hexdec( $m[2] ) );
704 }
705
706 return null; // give up
707 }
708
715 public static function sanitizeRange( $range ) {
716 list( /*...*/, $bits ) = self::parseCIDR( $range );
717 list( $start, /*...*/ ) = self::parseRange( $range );
718 $start = self::formatHex( $start );
719 if ( $bits === false ) {
720 return $start; // wasn't actually a range
721 }
722
723 return "$start/$bits";
724 }
725
732 public static function getSubnet( $ip ) {
733 $matches = [];
734 $subnet = false;
735 if ( IP::isIPv6( $ip ) ) {
736 $parts = IP::parseRange( "$ip/64" );
737 $subnet = $parts[0];
738 } elseif ( preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
739 // IPv4
740 $subnet = $matches[1];
741 }
742 return $subnet;
743 }
744}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
const RE_IPV6_WORD
Definition IP.php:37
const RE_IP_BYTE
Definition IP.php:29
const RE_IPV6_BLOCK
Definition IP.php:50
const RE_IPV6_GAP
Definition IP.php:52
const RE_IPV6_V4_PREFIX
Definition IP.php:53
const RE_IP_ADD
Definition IP.php:30
const RE_IP_BLOCK
Definition IP.php:33
const RE_IP_PREFIX
Definition IP.php:32
const RE_IPV6_PREFIX
Definition IP.php:38
const RE_IPV6_ADD
Definition IP.php:39
const IP_ADDRESS_STRING
Definition IP.php:56
A collection of public static functions to play with IP address and IP blocks.
Definition IP.php:67
static isValidBlock( $ipblock)
Validate an IP Block (valid address WITH a valid prefix).
Definition IP.php:126
static combineHostAndPort( $host, $port, $defaultPort=false)
Given a host name and a port, combine them into host/port string like you might find in a URL.
Definition IP.php:303
static isValid( $ip)
Validate an IP address.
Definition IP.php:113
static prettifyIP( $ip)
Prettify an IP for display to end users.
Definition IP.php:201
static isIPv4( $ip)
Given a string, determine if it as valid IP in IPv4 only.
Definition IP.php:101
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 IPSet $proxyIpSet
Definition IP.php:69
static formatHex( $hex)
Convert an IPv4 or IPv6 hexadecimal representation back to readable format.
Definition IP.php:320
static isIPAddress( $ip)
Determine if a string is as valid IP address or network (CIDR prefix).
Definition IP.php:79
static parseCIDR6( $range)
Convert a network specification in IPv6 CIDR notation to an integer network and a number of bits.
Definition IP.php:548
static IPv6ToRawHex( $ip)
Given an IPv6 address in octet notation, returns a pure hex string.
Definition IP.php:438
static canonicalize( $addr)
Convert some unusual representations of IPv4 addresses to their canonical dotted quad representation.
Definition IP.php:675
static getSubnet( $ip)
Returns the subnet of a given IP.
Definition IP.php:730
static parseRange6( $range)
Given a string range in a number of formats, return the start and end of the range in hexadecimal.
Definition IP.php:589
static sanitizeRange( $range)
Gets rid of unneeded numbers in quad-dotted/octet IP strings For example, 127.111....
Definition IP.php:713
static hexToQuad( $ip_hex)
Converts a hexadecimal number to an IPv4 address in quad-dotted notation.
Definition IP.php:354
static toHex( $ip)
Return a zero-padded upper case hexadecimal representation of an IP address.
Definition IP.php:405
static isPublic( $ip)
Determine if an IP address really is an IP address, and if it is public, i.e.
Definition IP.php:376
static hexToOctet( $ip_hex)
Converts a hexadecimal number to an IPv6 address in octet notation.
Definition IP.php:334
static isInRange( $addr, $range)
Determine if a given IPv4/IPv6 address is in a given CIDR network.
Definition IP.php:638
static isIPv6( $ip)
Given a string, determine if it as valid IP in IPv6 only.
Definition IP.php:90
static isInRanges( $ip, $ranges)
Determines if an IP address is a list of CIDR a.b.c.d/n ranges.
Definition IP.php:656
static parseCIDR( $range)
Convert a network specification in CIDR notation to an integer network and a number of bits.
Definition IP.php:458
static splitHostAndPort( $both)
Given a host/port string, like one might find in the host part of a URL per RFC 2732,...
Definition IP.php:254
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
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
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
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template to be included in the link
Definition hooks.txt:2902
processing should stop and the error should be shown to the user * false
Definition hooks.txt:189
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
MediaWiki has optional support for a high distributed memory object caching system For general information on but for a larger site with heavy like it should help lighten the load on the database servers by caching data and objects in Ubuntu and probably other Linux distributions If there s no package available for your you can compile it from epoll rt patch for Linux is current Memcached and libevent are under BSD style licenses The server should run on Linux and other Unix like systems you can run multiple servers on one machine or on multiple machines on a network
Definition memcached.txt:33